In your Xamarin Forms project, using the source nuget.orh, add the Colocator NuGet package (author - Crowd Connected)
In your Android project, in the MainActivity.cs file, add the following in the “OnCreate(Bundle savedInstanceState)” method after loading the application
CrossCurrentActivity.Current.Init(this, savedInstanceState);
Navigate to your Xamarin.iOS project and open Info.plist file
For more details about these permissions in the iOS section
Navigate to your Xamarin.Android project and open AndroidManifest.xml file from the Properties folder
In the Application tab, at Required Permissions section, enable:
Request location permission for both Android and iOS using Plugin.Permissions NuGet package or other preferred method.
Example using Plugin.Permissions
Go to your iOS project and add Plugin.Permissions NuGet
In your Main.cs file (or other preferred file) add the following method
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
...
static private async void AskForLocationPermission()
{
PermissionStatus status = await CrossPermissions.Current.RequestPermissionAsync<LocationAlwaysPermission>();
}
AskForLocationPermission();
Go to your Android project and add Plugin.Permissions NuGet
In your MainActivity.cs file (or other preferred file) add the following inside your “OnCreate(Bundle savedInstanceState)” method
ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }, 0);
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
You can use Colocator features for triggering the permission OS pop-ups whenever you want in your Forms application.
Import the plugin
using Colocator;
Create an instance of the plugin
IColocator colo = ColocatorMain.Instance;
Trigger permission pop-up
colo.TriggerBluetoothPermissionPopUp();
colo.TriggerMotionPermissionPopUp();
Start the library in your main project
Import the plugin
using Colocator;
Create an instance of the plugin
IColocator colo = ColocatorMain.Instance;
Start the library and set the delegate
colo.StartWithAppKey("YOUR_APP_KEY");
In the iOS project, the library should be started in AppDelegate.cs as follows:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
...
Colocator.ColocatorMain.Instance.StartWithAppKey("YOUR_APP_KEY");
...
}
We use background refresh to periodically check whether we should enable location tracking.
Enable Background Refresh by adding the following in your AppDelegate.cs file:
[Export("application:performFetchWithCompletionHandler:")]
public override void PerformFetch(UIApplication application, System.Action<UIBackgroundFetchResult> completionHandler)
{
Colocator.ColocatorMain.Instance.UpdateLibraryBasedOnClientStatusWithClientKey("CC_APP_KEY", false, completion: (result) =>
{
if (result)
{
completionHandler(UIBackgroundFetchResult.NewData);
}
else
{
completionHandler(UIBackgroundFetchResult.NoData);
}
});
}
We use Silent Push Notifications to enable location tracking at a given time.
Please enable Silent Push Notifications by doing the following in your AppDelegate.cs:
Ensure the app has notification permission
Registering for remote notifications
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
...
var authOptions = UserNotifications.UNAuthorizationOptions.Alert | UserNotifications.UNAuthorizationOptions.Badge | UserNotifications.UNAuthorizationOptions.Sound;
UserNotifications.UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => { });
UIApplication.SharedApplication.RegisterForRemoteNotifications();
...
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
byte[] bytes = deviceToken.ToArray<byte>();
string[] hexArray = bytes.Select(b => b.ToString("x2")).ToArray();
var token = string.Join(string.Empty, hexArray);
Colocator.ColocatorMain.Instance.AddAliasWithKey("apns_user_id", token);
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
NSString source = userInfo.ObjectForKey(new NSString("source")) as NSString;
if (source == "colocator")
{
Colocator.ColocatorMain.Instance.ReceivedSilentNotificationWithUserInfo(userInfo, "CC_APP_KEY", completion: (result) => {
if (result)
{
completionHandler(UIBackgroundFetchResult.NewData);
}
else
{
completionHandler(UIBackgroundFetchResult.NoData);
}
});
} else {
...
}
}
If required you can stop the library
ColocatorMain.Instance.Stop();
Aliases are key-value pairs. They are primarily used to send alternative IDs for a device, for example a unique Push Notification identifier. Go to the Push Notification Integrations page for more details
ColocatorMain.Instance.AddAliasWithKey("YOUR_KEY", "YOUR_VALUE");
Enable the foreground service ny doing the following
ColocatorMain.Instance.ActivateForegroundService("YOUR_TITLE", foregroundServiceIconID, "CHANNEL");
For indoor location and positioning, a few more steps need to be implemented
The latest location can be sent back to the device as updates. This is primarily used for displaying the location of the device on a map.
The location update callbacks contain a ColocatorLocationResponse object and they are deceived through a ColocatorDelegate
ColocatorMain.Instance.Delegate = new MyClass();
public class MyClass : ColocatorDelegate
{
...
public void DidReceiveLocation(ColocatorLocationResponse location)
{
// Use the location as you wish
// location.Latitude
// location.Longitude
// location.Error
// location.Timestamp
// location.HeaderOffset
// location.Floor
}
}
Request one location:
ColocatorMain.Instance.RequestLocation();
Request a stream of location updates:
ColocatorMain.Instance.RegisterLocationListener();
Please make sure you unregister from location callbacks when the user is not using the indoor map screen or navigation.
This is important for battery and performance optimization.
Stop the stream of updates:
ColocatorMain.Instance.UnregisterLocationListener();