0

I'm working on a Xamarin Forms app that communicates with a hardware device over BLE. If the app user decides to terminate the app by swiping up, I would like to notify the hardware device that the communication channel should be closed. The issue is that this communication is an async operation taking somewhere between 500ms and 1500ms. I dont care about the reply from the hardware device as I have no time to act on it anyways, due to my 5 sec window before the app process is gone, but I would like to ensure that the "shutdown" operation is sent to the device.

So far I've tried this to get it run synchronously, but the app crashes when I put the .Wait() on Task.Run - withoug .Wait() the "shutdown" is never sent to the device. How would I go about ensuring getting this async call to the hardware device?

Android:

        protected override void OnDestroy()
        {
            Task.Run(() => _appRestartService?.ShutDown()).Wait();
            base.OnDestroy();
        }

iOS

        public override void WillTerminate(UIApplication application)
        {
            Task.Run(() => _appRestartService?.ShutDown()).Wait();
        }

Exception on iOS:

System.AggregateException: One or more errors occurred. (A task was canceled.) ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00013] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:2029 
  at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:2759 
  at System.Threading.Tasks.Task.Wait () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:2625 
  at NameSpace.AppDelegate.WillTerminate (UIKit.UIApplication application) [0x00001] in /Users/X/src/App/AppProjectName/AppDelegate.cs:128 
  at (wrapper managed-to-native) UIKit.UIApplication.xamarin_UIApplicationMain(int,intptr,intptr,intptr,intptr&)
  at UIKit.UIApplication.UIApplicationMain (System.Int32 argc, System.String[] argv, System.IntPtr principalClassName, System.IntPtr delegateClassName) [0x00008] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.6/src/Xamarin.iOS/UIKit/UIApplication.cs:58 
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00013] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.6/src/Xamarin.iOS/UIKit/UIApplication.cs:84 
  at AppProjectName.Application.Main (System.String[] args) [0x00002] in /Users/X/src/App/AppProjectName/Main.cs:18 
---> (Inner Exception #0) System.Threading.Tasks.TaskCanceledException: A task was canceled.<---

Thanks in advance!

ruNury
  • 173
  • 2
  • 8
  • You have very little time to execute in `applicationWillTerminate` and it isn't guaranteed to run. What is your connection to the device? If it is a tcp socket or a BLE connection, then I would expect the device to get a connection close within a couple of seconds of the app being closed anyway. If you are using UDP then a periodic keep-alive is probably a more reliable approach. – Paulw11 Aug 30 '23 at 09:05
  • BLE. The connection is there already, so ideally it is just another command over an open connection. from a performance point this should not be an issue. The issue is that the device does not act on loss of connection by itself - I need to tell it that I will close this communication channel (BLE connection will prevail) – ruNury Aug 30 '23 at 09:22
  • That sounds like something you need to address in the device. BLE connections are inherently unreliable. The connection could fail at any time ven if the app is still running. – Paulw11 Aug 30 '23 at 10:24
  • Maybe I was unclear in my text. i dont intend to have the BLE closed - BLE connectivity is handled elsewhere. I simply want the hardware device to perform some task, in this case close a open communication channel, but the task could just as well be update some data in the device storage. The issue is to make the app stay alive long enough in order to run an async task in the context of app termination – ruNury Aug 30 '23 at 10:48
  • That isn't going to happen on iOS. – Paulw11 Aug 30 '23 at 11:14
  • At least on Android, you can use L2CAP CoC to set up a communication channel between the app and the remote BLE device. The remote device will be notified when the app terminates, as the channel will be closed, even if other apps running on Android have a BLE connection open to the same device. If your app is the only one running on the phone having a connection open to the device, then the connection will terminate gracefully and the remote device will be notified by the disconnect event. – Emil Aug 30 '23 at 13:46

0 Answers0