Как получить доступ к сервису переднего плана из WebView Javascript Bridge - PullRequest
0 голосов
/ 29 марта 2020

Я постараюсь объяснить все, что в моих силах, но я новичок в использовании Xamarin, поэтому, пожалуйста, потерпите меня, пока я пытаюсь дать вам понимание моей ситуации.

Я использую Xamarin Формы для создания приложения Android, у меня уже есть настольное приложение, которое использует Electron, поэтому у меня есть много встроенных пользовательских интерфейсов в HTML, которые я использую в HybridWebView для интерфейса и JSBridge для вызова C# code.

Мое приложение будет установлено только в клиентской сети устройств, и мы настроили службу переднего плана, которая имеет служебное уведомление для поддержки выполнения фоновых заданий; все это работает по назначению.

Вызов C# кода из интерфейса HTML достаточно прост с использованием JSBridge / HybridWebView, однако я не могу найти способ, позволяющий моим C# функциям внутри класс JSBridge для связи с моей службой переднего плана, которая уже была запущена MainActivity, эта служба запускает фоновые задания, которые возвращают данные, к которым мой интерфейс должен иметь доступ.

Моя служба запускается в MainActivity OnCreate, как Итак:

Intent startServiceIntent = new Intent(this, typeof(NotificationService));
StartService(startServiceIntent);

Сервис довольно базовый c и выглядит так:

[Service]
public class NotificationService : Service
{

   public int SomeDataFromBackgroundJob { get; set; }

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

   public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
   {
      RegisterForegroundService();
      // This tells Android not to restart the service if it is killed to reclaim resources.
      return StartCommandResult.Sticky;
   }

   public override IBinder OnBind(Intent intent)
   {
      return null;
   }

   public override void OnDestroy()
   {
      //Destroy background jobs
      base.OnDestroy();
   }

   void RegisterForegroundService()
   {
      // Enlist this instance of the service as a foreground service
      StartForeground(Constants.NOTIFICATION_SERVICE_UNIQUE_APP_ID, BuildNotification());
   }        

   Notification BuildNotification()
   {
      if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
      {
         var channel = new NotificationChannel(Constants.NOTIFICATION_SERVICE_CHANNEL_ID, Constants.NOTIFICATION_SERVICE_CHANNEL_NAME, NotificationImportance.Min);
         channel.LightColor = Color.Blue;
         channel.EnableVibration(false);
         channel.LockscreenVisibility = NotificationVisibility.Secret;
         var service = GetSystemService(Context.NotificationService) as NotificationManager;

         service.CreateNotificationChannel(channel);
      }

      var notificationBuilder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_SERVICE_CHANNEL_ID);
      var notification = notificationBuilder.SetOngoing(true)
         .SetContentTitle($"Tap to see account status: {number}")
         .SetContentIntent(BuildIntentToShowMainActivity())
         .SetSmallIcon(Resource.Mipmap.icon) //Resource.Drawable.ic_stat_name)
         .SetPriority((int)NotificationPriority.Min)
         .SetCategory(Notification.CategoryService)
         .Build();

      return notification;
   }
   //Sniped background job code
}

Мой код JSBridge:

public class JSBridge : Java.Lang.Object
{
    readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

    public JSBridge(HybridWebViewRenderer hybridRenderer)
    {
        hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
    }

    [JavascriptInterface]
    [Export("IsUserLoggedIn")]
    public string IsUserLoggedIn()
    {
        //WebView.Uri = "login.html";
        //This returns a null object for the service, because its a "normal foreground service, not a dependancy"
        if (DependencyService.Get<NotificationService>().SomeDataFromBackgroundJob == 3)
        {
            //Got data from background job
            return "Something to return to the UI/JS";
        }

        return null;
    }

    public HybridWebView WebView
    {
        get
        {
            HybridWebViewRenderer hybridRenderer;

            if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
            {
                return ((HybridWebView)hybridRenderer.Element);
            }

            return null;
        }
    }
}

Как видите внутри IsUserLoggedIn (пример функции, которую я сделал) я пытался использовать DependencyService.Get, но он возвращает нулевой объект. Важно, чтобы у моего IsUserLoggedIn был доступ к тому же экземпляру NotificationService, который был запущен моим MainActivity, потому что фоновые задания критичны для бизнеса и на большинстве устройств требуют много времени.

Я думаю, что это должно быть довольно нормальный вариант использования (особенно если вы игнорируете тот факт, что я использую HTML пользовательский интерфейс), и я уверен, что должен быть способ сделать это.

Любые советы и пожелания будут оценены.

1 Ответ

0 голосов
/ 29 марта 2020

Как предполагает SushiHangover, использование связанной службы - это путь к go.

Документация не очень полезна, и хотя в ней говорится, что связанная служба вызывает OnBind () для запуска, в ней также упоминается что он также может вызвать OnStartCommand. Однако в документации не упоминается, что для запуска OnStartCommand необходимо вызвать StartService, а также BindService.

Пример:

Intent startServiceIntent = new Intent(this, typeof(NotificationService));
BindService(startServiceIntent, serviceConnection, Bind.AutoCreate);
StartService(startServiceIntent);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...