I'm trying to create an app. Here I'm trying to get the user's current location by clicking the button. But it produces an exception like Not Implemented exception - This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation
Already I did clean and rebuild the solution.
And I've enabled the permission for access_fine_location,
access_coarse_location.
I've added plugin.current and add an activity inside the mainactivity.cs
file.
string answer ="";
try
{
await CrossGeolocator.Current.StartListeningAsync(new
TimeSpan(20000),10);
if (CrossGeolocator.Current.IsListening)
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var position = await
locator.GetPositionAsync(TimeSpan.FromSeconds(20000));
string lat = position.Latitude.ToString();
string lon = position.Longitude.ToString();
answer = lat + lon;
}
else
{
answer= "Not listening";
}
}
catch (Exception ex)
{
answer= ex.Message;
}
I need the result which contains the longitude and latitude values.
What I've to do in my project?
Edited :
public async Task<String> GetLastKnownLocationAsync()
{
Position ObjPosition = null;
try
{
await DependencyService.Get<IGeolocator>().StartListeningAsync(new TimeSpan(20000), 10);
if (CrossGeolocator.Current.IsListening)
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
ObjPosition = await DependencyService.Get<IGeolocator>().GetPositionAsync(TimeSpan.FromSeconds(20));
string lat = ObjPosition.Latitude.ToString();
string lon = ObjPosition.Longitude.ToString();
Info = lat + lon;
}
else
{
Info = "Not listening";
}
return Info;
}
catch (Exception ex)
{
Info = ex.Message;
return Info;
}
}
I'm getting error on the sixth line.
I have implemented GPS tracking functionality in my Xamarin.Forms application too. And as per my personal experience, Geolocator plugin doesn't work as expected with Xamarin.Forms and also have some issues and limitations too. This plugin is developed by taking reference of Xamarin Essentials Geolocation. I will suggest that you should use Xamarin Essentials instead of Geolocator plugin as it is well documented and easy to implement without any major issues. You can find step by step guid to implement Xamarin Essentials Geolocation from following link:
https://learn.microsoft.com/en-us/xamarin/essentials/geolocation?tabs=android
Did you install the NuGet package on both your shared project as well as your platform projects? The error message, in this case, is quite accurate. What basically happens here is that this plugin installs a form of dependency service that has a platform-specific implementation and just an interface on your shared project.
For some reason, your calls end up in the shared code, which only implements this exception to let you know you're in the wrong place. This is usually due to not having the package installed on your platform project, or, the package being "optimized away" by the linker. This tends to happen because the compiler notices there is no reference from your project to this library, so it strips it to let it take up less space.
To make sure this last thing doesn't happen, you can go into your platform project, in this case, Android and go into the MainActivity.cs and add a dummy reference to an object in this plugin. For instance, add this:
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
// THIS WAS ADDED
var foo = new Plugin.Geolocator.Abstractions.Address();
LoadApplication(new App());
}
This is actually the reason a lot of these libraries used to have an Init method.
Having said all this, I actually have to agree with Akshay in the other answer and if at all possible, you probably want to look at upgrading your project to use .NET Standard and move to the Xamarin.Essentials library which takes all of this pain away.
Here is a little advice for you, that I usually use: if you have an issue and can't resolve it, try to create a separate little project with step-by-step tutorial of how that works. Usually it works, and you can find out what exactly wrong with your main solution.
EDIT:
Link to DependencyService
Shortly, you have to create Interface that would be used by you, i.e. IMyInterface. After that, write platform-specific classes for Android/iOS with interface implementation. When you write it, you can use the methods like so:
DependencyService.Get<IMyInterface>().YourMethod().
EDIT 2:
You have to add this for your platform-specific classes:
[assembly: Dependency(typeof(MyCustomClass))] // Check this assembly
namespace ISSO_I.Droid.PlatformSpecific
{
public class MyCustomClass: IMyInterface
{
/// your code here
}
}
EDIT 3:
Call location Updates:
protected override void OnAppearing()
{
base.OnAppearing();
ToIssoView = false;
RequestLocationUpdates(); // Call this method
}
Method to request location updates:
public async void RequestLocationUpdates()
{
/// check permission for location updates
var hasPermission = await CommonStaffUtils.CheckPermissions(Permission.Location);
if (!hasPermission)
return;
if (CrossGeolocator.Current.IsListening) return;
MyMap.MyLocationEnabled = true;
CrossGeolocator.Current.PositionChanged += Current_PositionChanged;
CrossGeolocator.Current.PositionError += Current_PositionError;
await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(1), 5);
}
public static async Task<bool> CheckPermissions(Permission permission)
{
var permissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
var request = false;
if (permissionStatus == PermissionStatus.Denied)
{
if (Device.RuntimePlatform == Device.iOS)
{
var title = $"{permission} Permission";
var question = $"To use this plugin the {permission} permission is required. Please go into Settings and turn on {permission} for the app.";
const string positive = "Settings";
const string negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return false;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return false;
}
request = true;
}
if (!request && permissionStatus == PermissionStatus.Granted) return true;
{
var newStatus = await CrossPermissions.Current.RequestPermissionsAsync(permission);
if (!newStatus.ContainsKey(permission) || newStatus[permission] == PermissionStatus.Granted) return true;
var title = $"{permission} Permission";
var question = $"To use the plugin the {permission} permission is required.";
const string positive = "Settings";
const string negative = "Maybe Later";
var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
if (task == null)
return false;
var result = await task;
if (result)
{
CrossPermissions.Current.OpenAppSettings();
}
return false;
}
}
Related
After long searching I decided to ask here.
How can i control DC motors with Pololu DRV8835 Motor Driver?
I tried to use Microsoft.IoT.Lightning library, but frequency seems to be too low. In Python library for this driver frequency is 20 kHz.
When I tried to modify this library, build threw exception because of non-existing targets (but they didn't even appeared after library building).
This is my code:
public async Task Initialize()
{
try
{
if (!LightningProvider.IsLightningEnabled)
{
throw new Exception("No lightning provider detected!");
}
LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
Gpio = await GpioController.GetDefaultAsync();
APhase = Gpio.OpenPin(19);
BPhase = Gpio.OpenPin(6);
APhase.SetDriveMode(GpioPinDriveMode.Output);
BPhase.SetDriveMode(GpioPinDriveMode.Output);
Pwm = await PwmController.GetDefaultAsync();
Pwm.SetDesiredFrequency(1000);
AEnable = Pwm.OpenPin(26);
BEnable = Pwm.OpenPin(13);
}
catch (Exception e)
{
throw e;
}
}
private bool stopMove = true;
private double speed = 1;
public void StopMove()
{
stopMove = true;
}
public async Task MoveForward()
{
await Task.Delay(1);
stopMove = false;
APhase.Write(GpioPinValue.Low);
BPhase.Write(GpioPinValue.Low);
AEnable.SetActiveDutyCyclePercentage(speed);
BEnable.SetActiveDutyCyclePercentage(speed);
Debug.WriteLine("Starting...");
AEnable.Start();
BEnable.Start();
while (!stopMove) { }
AEnable.Stop();
BEnable.Stop();
AEnable.SetActiveDutyCyclePercentage(0);
BEnable.SetActiveDutyCyclePercentage(0);
}
public async Task MoveBackward()
{
await Task.Delay(1);
stopMove = false;
APhase.Write(GpioPinValue.High);
BPhase.Write(GpioPinValue.High);
AEnable.SetActiveDutyCyclePercentage(speed);
BEnable.SetActiveDutyCyclePercentage(speed);
AEnable.Start();
BEnable.Start();
while (!stopMove) { }
AEnable.Stop();
BEnable.Stop();
AEnable.SetActiveDutyCyclePercentage(0);
BEnable.SetActiveDutyCyclePercentage(0);
}
Does anyone know any working solution?
There are two ways you can have a try:
First, using Microsoft.IoT.Lightning library. There are two PWM control providers:
Software simulate PWM. But you can see the max frequency is 1kHz. In order to use higher frequency you can modify the constant and reference the lightning source code for you project, instead of the nugget one. However, Since it’s using software timing, you might have slewed waveforms in you make aggressive attempt.
PCA9685. For doing this you need a external PCA9685 module and some electronic circuits. Likewise, you need reference source code the modify the max frequency that defined.
Second, using the out of box driver BSP. This driver support on-chip PWM hardware. Try to use higher frequency to see if the signal generated meets your requirement.
I need to upgrade our service bus nuget package to 3.2.2 (think the evenprocessor host requires it) but I have always kept our service bus project lib at 2.8.2. This is mainly due to the fact that BeginReceive() and EndReceive() looks to have been removed. Is there any reason or anyway I can easily convert this
public void StartReceiving(RecieverCallback callback, TimeSpan waittime, object state = null)
{
this._recieverCallback = callback;
_queueClient = this.MessagingFactory.CreateQueueClient(QueueName, ReceiveMode);
// make initial async call
_asyncresult = _queueClient.BeginReceive(waittime, ReceiveDone, _queueClient);
}
public void ReceiveDone(IAsyncResult result)
{
if (result != null)
{
try
{
var tmpClient = result.AsyncState as QueueClient;
var brokeredMessage = tmpClient.EndReceive(result);
if (brokeredMessage != null)
{
if (ReceiveMode == ReceiveMode.PeekLock)
{
brokeredMessage.Complete();
}
var tmpMessage = brokeredMessage.GetBody<T>();
ProcessMessageProperties(tmpMessage, brokeredMessage);
_recieverCallback(tmpMessage);
}
}
catch (Exception ex)
{
_logger.Fatal("ReceiveDone: {0}", ex.Message);
Console.WriteLine(ex.Message);
}
}
// do recieve for next message
_asyncresult = _queueClient.BeginReceive(ReceiveDone, _queueClient);
}
Image showing the error
Following image shows what happens if I upgrade servicebus to 3.2.2 which I believe will solve the original error (program running 3.2.2, lib project running 2.8.x)
I figured it out see link
https://gist.github.com/sitereactor/8953583
If anyone has a similar issue, let me know and will post my code but its 95% the same as per the link.
Scratching my head on this one.
I've got a background task in my UWP application which is registered to run every 15 minutes (using TimeTrigger) and whenever the internet becomes available (using a SystemTrigger). I know for a fact that these are registered correctly as both appear in the "Lifecycle Events" when debugging using visual studio. Nevertheless, my code for registering them is below:
bool registered1 = false;
bool registered2 = false;
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == "BackgroundGPS")
{
registered1 = true;
}
if (task.Value.Name == "InternetAvailGPS")
{
registered2 = true;
}
}
await BackgroundExecutionManager.RequestAccessAsync();
if (!registered1)
{
var builder1 = new BackgroundTaskBuilder();
builder1.Name = "BackgroundGPS";
builder1.TaskEntryPoint = "BackgroundTasks.BackgroundGPSTask";
var triggerTime = new TimeTrigger(15, false);
builder1.SetTrigger(triggerTime);
BackgroundTaskRegistration task1 = builder1.Register();
}
if (!registered2)
{
var builder2 = new BackgroundTaskBuilder();
builder2.Name = "InternetAvailGPS";
builder2.TaskEntryPoint = "BackgroundTasks.BackgroundGPSTask";
var triggerIA = new SystemTrigger(SystemTriggerType.InternetAvailable, false);
builder2.SetTrigger(triggerIA);
BackgroundTaskRegistration task2 = builder2.Register();
}
I have ensured that the tasks are declared correctly in my manifest. If they weren't, my app would be throwing an exception when trying to register them.
If I run in debug mode I can see that both BackgroundGPS and InternetAvailGPS are shown in the Lifecycle Events. However, when I click on either of them to force them to execute, I get the following in the output window:
The program '[4728] backgroundTaskHost.exe' has exited with code 1 (0x1).
I have a breakpoint set at the first line of code in my 'Run' method of the background task but this is never hit. The background task is never loaded nor run, and I've no idea why. This probably isn't an issue with my Run method, but it looks like this (I've omitted much of the meat of it, and just included the beginning and end)
public async void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("GPS Started");
int errCode = 0;
try
{
_deferral = taskInstance.GetDeferral();
saveGPSStatus(DateTime.Now.ToString(), "", " ");
var access = await Geolocator.RequestAccessAsync();
if (access != GeolocationAccessStatus.Allowed)
{
Debug.WriteLine("No access");
saveGPSStatus("", "", "No GPS Access");
return;
}
Geolocator locator = new Geolocator();
locator.DesiredAccuracyInMeters = 100;
Geoposition position = await locator.GetGeopositionAsync();
//Stuff goes on in here
_deferral.Complete();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
saveGPSStatus("", "", "Unexpected error. Err code "+errCode+". " + e.Message);
_deferral.Complete();
}
}
I have tried this both on a Windows Phone and a Windows Tablet both running build 10.0.10586.164, and they both do not execute my background task.
As I said above, these were working perfectly a few weeks ago and have only realised something was wrong as some of the app's users have been complaining!
Any help is greatly appreciated.
Got it working in the end, I was simply missing a reference to my background task project within my main project. I must have deleted it by accident at some point before that.
Just to expand on not having it referenced, not having the correct TaskEntryPoint namespace and class name will also cause this error. For me, I misspelt the class name.
I am working on integrating the geolocator plugin into my Xamarin.Forms app. I have installed the nuget package into .core, .droid & .ios. I haven't added it the the other projects in the solution, as I am on mac and they aren't supported.
I have added the example snippet (less the print to console lines), but it is throwing compiler errors. I have added using Geolocator; at the top, but the var position line throws error - the 'await' operator can only be used when its containing method is marked with the 'async' modifier - What have I done wrong?
I have included a screen shot below:
[![Compiler Errors][1]][1]
Any thoughts would be much appreciated.
UPDATE
My code now runs, I have the following structure:
namespace MyApp
{
public partial class HomePage : ContentPage
{
// Class Definitions
public HomePage(IAdapter adapter)
{
InitializeComponent();
this.adapter = adapter;
var LocManager = new CLLocationManager();
LocManager.AuthorizationChanged += (sender, args) => {
Debug.WriteLine ("Authorization changed to: {0}", args.Status);
};
if (UIDevice.CurrentDevice.CheckSystemVersion(8,0))
LocManager.RequestAlwaysAuthorization();
NewDeviceButton.Clicked += async (sender, e) => {
//Code which I would like to be able to use GetLatitude.
}
}
async Task<double> GetLongitude()
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);
var longitude = position.Longitude;
return longitude;
}
}
However, I get the following error message.
On iOS 8.0 and higher you must set either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in your Info.plist file to enable Authorization Requests for Location updates! I originally only had the async method, but having seen the error message and reading your app note, I added the additional code at the top to try and authorise location services. However, I now get an error message saying Error CS0246: The type or namespace name 'CLLocationManager' could not be found. Are you missing an assembly reference? (CS0246) this shows on the var LocManager line. Why is this and what should I do to fix it?
It's normal an await method need to be run in an async method.
Therefore, you need to call your method in the OS projects.
Here the steps to work with geolocator plugin :
Create an interface on your xamarin form project:
public interface ILocation
{
Task<Position> GetLocation();
}
Create a class in your OS project ( Android, IOS or WP )
Here the exemple for Android
public class Location_Android : Activity, ILocation
{
public async Task<Position> GetLocation()
{
return await GetPosition();
}
private async Task<Position> GetPosition()
{
Position result = null;
try
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
if (locator.IsListening != true)
{
locator.StartListening(minTime: 1000, minDistance: 0);
}
var position = await locator.GetPositionAsync(10000);
//You can use Xamarin.Forms.Maps.Position
//Here I use a personnal class
result = new Position(position.Longitude, position.Latitude);
}
catch (Exception e)
{
Log.Debug("GeolocatorError", e.ToString());
}
return result;
}
}
On your class call the method like that
var position = await DependencyService.Get<ILocation>().GetLocation();
Hope this can help you.
I'm working on WinRT. If an unhandled exception is thrown I want to write the message text to the storage.
I added an Event handler in 'App.xaml.cs', see the code.
The exception is caught but the last line, where the file is written, crashes again -> 'exception'!
Why? Any idea?
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += App_UnhandledException;
}
async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file= await folder.CreateFileAsync("crash.log",CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, e.Message); // <----- crash again -----
}
Thanks
Sunny
I've been wondering the same thing and stumbled across this quite early on in my search. I've figured out a way, hopefully this will prove useful to someone else too.
The problem is that await is returning control of the UI thread and the app's crashing. You need a deferral but there's no real way to get one.
My solution is to use the settings storage, instead. I'm assuming most people wanting to do this want to do something LittleWatson style, so here's some code modified from http://blogs.msdn.com/b/andypennell/archive/2010/11/01/error-reporting-on-windows-phone-7.aspx for your convenience:
namespace YourApp
{
using Windows.Storage;
using Windows.UI.Popups;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
public class LittleWatson
{
private const string settingname = "LittleWatsonDetails";
private const string email = "mailto:?to=you#example.com&subject=YourApp auto-generated problem report&body=";
private const string extra = "extra", message = "message", stacktrace = "stacktrace";
internal static void ReportException(Exception ex, string extraData)
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = extraData;
exceptionValues[message] = ex.Message;
exceptionValues[stacktrace] = ex.StackTrace;
}
internal async static Task CheckForPreviousException()
{
var container = ApplicationData.Current.LocalSettings.Containers;
try
{
var exceptionValues = container[settingname].Values;
string extraData = exceptionValues[extra] as string;
string messageData = exceptionValues[message] as string;
string stacktraceData = exceptionValues[stacktrace] as string;
var sb = new StringBuilder();
sb.AppendLine(extraData);
sb.AppendLine(messageData);
sb.AppendLine(stacktraceData);
string contents = sb.ToString();
SafeDeleteLog();
if (stacktraceData != null && stacktraceData.Length > 0)
{
var dialog = new MessageDialog("A problem occured the last time you ran this application. Would you like to report it so that we can fix the error?", "Error Report")
{
CancelCommandIndex = 1,
DefaultCommandIndex = 0
};
dialog.Commands.Add(new UICommand("Send", async delegate
{
var mailToSend = email.ToString();
mailToSend += contents;
var mailto = new Uri(mailToSend);
await Windows.System.Launcher.LaunchUriAsync(mailto);
}));
dialog.Commands.Add(new UICommand("Cancel"));
await dialog.ShowAsync();
}
}
catch (KeyNotFoundException)
{
// KeyNotFoundException will fire if we've not ever had crash data. No worries!
}
}
private static void SafeDeleteLog()
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = string.Empty;
exceptionValues[message] = string.Empty;
exceptionValues[stacktrace] = string.Empty;
}
}
}
To implement it, you need to do the same as the link above says, but to ensure the data's here in case the url ever goes down:
App.xaml.cs Constructor (BEFORE the call to this.InitializeComponent()):
this.UnhandledException += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Obviously if you already have an UnhandledException method you can throw the call to LittleWatson in there.
If you're on Windows 8.1, you can add a NavigationFailed call too. This needs to be in an actual page (typically MainPage.xaml.cs or whatever page is first opened):
xx.xaml.cs Constructor (any given page):
rootFrame.NavigationFailed += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Lastly, you need to ask the user if they want to send the e-mail when the app re-opens. In your app's default Page's constructor (default: the page App.xaml.cs initializes):
this.Loaded += async (s, e) => await LittleWatson.CheckForPreviousException();
Or add the call to your OnLoad method if you already use it.
In this situation, await could be loosely translated to "do this job on another thread, and continue what you were doing while you wait for it to finish". Given that what your app was doing was crashing, you probably don't want it to continue doing that until you're done logging the problem. I'd suggest running your file IO synchronously in this case.
This may come a bit too late for the original question but...
as #Hans Passant suggested, avoiding await (i.e., running the FileIO.AppendTextAsync() synchronously), also seconded by #Jon, I would opt for this rather than the relatively too heavy code for LittleWatson. As the app is in some error handing state anyway (this should be a rare occurrence) I wouldn't put any blocking arising from synchronous (due to removing await) as a major downside.
Leaving the synchronous option to one side, the following await implementation worked for me:
Change await FileIO.AppendTextAsync(file, e.Message); to:
Task task = LogErrorMessage(file, e.Message)
task.Wait(2000); // adjust the ms value as appropriate
...
private async Task LogErrorMessage(StorageFile file, string errorMessage)
{
await FileIO.AppendTextAsync(file, errorMessage); // this shouldn't crash in App_UnhandledException as it did before
}