AppService in Xamarin

Hi everybody,
I would like to know if someone else has faced to the AppService in Xamarin. I'm going now to explain my situation.
I have developed in the past an UWP App with implemented an AppService feature (for communicate with a browser extension through interoperability with a Native Messaging Host application).
In this months I started to upgrade my App with Xamarin (for get improvement with the cross platform features).
I don't need to use an AppService for Android or iOS, but for UWP I would like to get it.
I found that the OnBackgroundActivated function is not called (in the Platform Specific Project for UWP).
I know that I can create a background task out-of-process but I don't know if it is the best (or the only) solution for an AppService.

First at all, why the OnBackgroundActivated is not called? Is it not expected in Xamarin Forms?

Thank you,

Regards

Best Answer

  • MatVicMatVic ✭✭
    Accepted Answer

    Not without a little of embarrassment, the AppService is working now :/ !
    I tryed to build a UWP Runtime Component for create a out-of -process background task and the OnBackgroundActivated function of the Platform Specific Project has been called... maybe I forgot to do something yesterday.

    For complete my answer, I would like to post how it works:

    In the Platform Specific Project of UWP, override the function OnBackgroundActivated

    private BackgroundTaskDeferral AppServiceDeferral = null;
    private AppServiceConnection Connection = null;
    private int CurrentConnectionIndex = 0;
    
    private static int ConnectionIndex = 0;
    private static Dictionary<int, AppServiceConnection> Connections = new Dictionary<int, AppServiceConnection>();
    private static Dictionary<int, BackgroundTaskDeferral> AppServiceDeferrals = new Dictionary<int, BackgroundTaskDeferral>();
    private static object ThisLock = new object();
    ...
    protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
    {
        base.OnBackgroundActivated(args);
        IBackgroundTaskInstance taskInstance = args.TaskInstance;
    
            if (taskInstance.TriggerDetails is AppServiceTriggerDetails)
            {
                AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    
                AppServiceDeferral = taskInstance.GetDeferral();
                taskInstance.Canceled += OnAppServicesCanceled;
                Connection = appService.AppServiceConnection;
                Connection.RequestReceived += OnAppServiceRequestReceived;
                Connection.ServiceClosed += AppServiceConnection_ServiceClosed;
    
                // Critical section
                lock (ThisLock)
                {
                    Connection.AppServiceName = ConnectionIndex.ToString();
                    Connections.Add(ConnectionIndex, Connection);
                    AppServiceDeferrals.Add(ConnectionIndex, AppServiceDeferral);
                    ConnectionIndex++;
                 }
            }
    }
    

    Implement the ServiceClosed callback

    private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
    {
            try
            {
                CurrentConnectionIndex = int.Parse(sender.AppServiceName);
                AppServiceDeferral = AppServiceDeferrals[CurrentConnectionIndex];
                AppServiceDeferrals.Remove(CurrentConnectionIndex);
    
                if (AppServiceDeferral != null)
                {
                    AppServiceDeferral.Complete();
                    AppServiceDeferral = null;
                }
            }
            catch (Exception Ex)
            {
                Debug.WriteLine("AppServiceConnection_ServiceClosed error: " + Ex.Message);
            }
    }
    

    And the ServiceCanceled callback

    private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
                AppServiceTriggerDetails appService = sender.TriggerDetails as AppServiceTriggerDetails;
    
                try
                {
                    CurrentConnectionIndex = int.Parse(appService.AppServiceConnection.AppServiceName);
                    AppServiceDeferral = AppServiceDeferrals[CurrentConnectionIndex];
                    AppServiceDeferrals.Remove(CurrentConnectionIndex);
    
                    if (AppServiceDeferral != null)
                    {
                        AppServiceDeferral.Complete();
                        AppServiceDeferral = null;
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("OnAppServicesCanceled error: " + Ex.Message);
                }
    }
    

    Now, implement the RequestReceived callback for elaborate your request

    private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
    {
                AppServiceDeferral messageDeferral = args.GetDeferral();
    
                try
                {
                    // Your request message is here args.Request.Message
                    // Consume the request and answer with await args.Request.SendResponseAsync(message);
                }
                finally
                {
                    messageDeferral.Complete();
                }
    }
    

    Remember to set the declaration of your UWP project: add the App Service support with the correct Name

Answers

  • MatVicMatVic Member ✭✭
    Accepted Answer

    Not without a little of embarrassment, the AppService is working now :/ !
    I tryed to build a UWP Runtime Component for create a out-of -process background task and the OnBackgroundActivated function of the Platform Specific Project has been called... maybe I forgot to do something yesterday.

    For complete my answer, I would like to post how it works:

    In the Platform Specific Project of UWP, override the function OnBackgroundActivated

    private BackgroundTaskDeferral AppServiceDeferral = null;
    private AppServiceConnection Connection = null;
    private int CurrentConnectionIndex = 0;
    
    private static int ConnectionIndex = 0;
    private static Dictionary<int, AppServiceConnection> Connections = new Dictionary<int, AppServiceConnection>();
    private static Dictionary<int, BackgroundTaskDeferral> AppServiceDeferrals = new Dictionary<int, BackgroundTaskDeferral>();
    private static object ThisLock = new object();
    ...
    protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
    {
        base.OnBackgroundActivated(args);
        IBackgroundTaskInstance taskInstance = args.TaskInstance;
    
            if (taskInstance.TriggerDetails is AppServiceTriggerDetails)
            {
                AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    
                AppServiceDeferral = taskInstance.GetDeferral();
                taskInstance.Canceled += OnAppServicesCanceled;
                Connection = appService.AppServiceConnection;
                Connection.RequestReceived += OnAppServiceRequestReceived;
                Connection.ServiceClosed += AppServiceConnection_ServiceClosed;
    
                // Critical section
                lock (ThisLock)
                {
                    Connection.AppServiceName = ConnectionIndex.ToString();
                    Connections.Add(ConnectionIndex, Connection);
                    AppServiceDeferrals.Add(ConnectionIndex, AppServiceDeferral);
                    ConnectionIndex++;
                 }
            }
    }
    

    Implement the ServiceClosed callback

    private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
    {
            try
            {
                CurrentConnectionIndex = int.Parse(sender.AppServiceName);
                AppServiceDeferral = AppServiceDeferrals[CurrentConnectionIndex];
                AppServiceDeferrals.Remove(CurrentConnectionIndex);
    
                if (AppServiceDeferral != null)
                {
                    AppServiceDeferral.Complete();
                    AppServiceDeferral = null;
                }
            }
            catch (Exception Ex)
            {
                Debug.WriteLine("AppServiceConnection_ServiceClosed error: " + Ex.Message);
            }
    }
    

    And the ServiceCanceled callback

    private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
                AppServiceTriggerDetails appService = sender.TriggerDetails as AppServiceTriggerDetails;
    
                try
                {
                    CurrentConnectionIndex = int.Parse(appService.AppServiceConnection.AppServiceName);
                    AppServiceDeferral = AppServiceDeferrals[CurrentConnectionIndex];
                    AppServiceDeferrals.Remove(CurrentConnectionIndex);
    
                    if (AppServiceDeferral != null)
                    {
                        AppServiceDeferral.Complete();
                        AppServiceDeferral = null;
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("OnAppServicesCanceled error: " + Ex.Message);
                }
    }
    

    Now, implement the RequestReceived callback for elaborate your request

    private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
    {
                AppServiceDeferral messageDeferral = args.GetDeferral();
    
                try
                {
                    // Your request message is here args.Request.Message
                    // Consume the request and answer with await args.Request.SendResponseAsync(message);
                }
                finally
                {
                    messageDeferral.Complete();
                }
    }
    

    Remember to set the declaration of your UWP project: add the App Service support with the correct Name

Sign In or Register to comment.