Как вызвать плагин Cordova, используя Angular без Ionic - PullRequest
0 голосов
/ 15 ноября 2018

Я создал PWA в Angular 6 и намеревался использовать API Карт Google для целей геолокации. Однако вскоре я понял, что сервисы геолокации в PWA работают только тогда, когда пользователь взаимодействует с пользовательским интерфейсом, чтобы преднамеренно запросить их местоположение. Однако мое приложение должно отслеживать местоположение пользователей в фоновом режиме, пока они ездят. Поэтому, когда они блокируют экран или переходят в другое приложение, они все равно должны отслеживать их. Напомним, что это частное приложение, и пользователи полностью знают, что они отслеживаются. В результате я преобразовал PWA в гибридное приложение, используя Cordova. Пока все работает с тем, что у меня уже было (эмуляция в порядке и т. Д.), Но я не могу понять, как добавить часть геолокации. Я установил этот плагин, который, кажется, установлен и доступен. Все примеры, которые я видел, используют Ionic (который мне не нужен на данный момент) и предназначены для сценария, когда пользователь нажимает кнопку, чтобы узнать свое местоположение, но он мне нужен, когда материал геолокации находится в службе и запускается. работает в фоновом режиме после того, как они вошли в систему. Я не могу найти то, что показывает, как это сделать. Вот что я думал, что должен сделать:

(это не завершено, я просто вставил здесь пример кода из GitHub и намереваюсь заполнить его "материалом", когда я знаю, что он на самом деле вызывается)

_services / geolocation.service.ts:

import { Injectable } from '@angular/core';
import { Component, ViewChild } from '@angular/core';

declare var cordova: any;

@Injectable()
export class GeolocationService {
  startBackgroundGeolocation() {
    console.log("Geolocation service called...");
    cordova.plugins.BackgroundGeolocation.configure({
      locationProvider: cordova.plugins.BackgroundGeolocation.ACTIVITY_PROVIDER,
      desiredAccuracy: cordova.plugins.BackgroundGeolocation.HIGH_ACCURACY,
      stationaryRadius: 50,
      distanceFilter: 50,
      notificationTitle: 'Background tracking',
      notificationText: 'enabled',
      debug: true,
      interval: 10000,
      fastestInterval: 5000,
      activitiesInterval: 10000,
      url: 'http://192.168.0.3:3000/location',
      httpHeaders: {
        'X-FOO': 'bar'
      },
      // customize post properties
      postTemplate: {
        lat: '@latitude',
        lon: '@longitude',
        foo: 'bar' // you can also add your own properties
      }
    });

    cordova.plugins.BackgroundGeolocation.on('location', function(location) {
      // handle your locations here
      // to perform long running operation on iOS
      // you need to create background task
      cordova.plugins.BackgroundGeolocation.startTask(function(taskKey) {
        // execute long running task
        // eg. ajax post location
        // IMPORTANT: task has to be ended by endTask
        cordova.plugins.BackgroundGeolocation.endTask(taskKey);
      });
    });

    cordova.plugins.BackgroundGeolocation.on('stationary', function(stationaryLocation) {
      // handle stationary locations here
    });

    cordova.plugins.BackgroundGeolocation.on('error', function(error) {
      console.log('[ERROR] cordova.plugins.BackgroundGeolocation error:', error.code, error.message);
    });

    cordova.plugins.BackgroundGeolocation.on('start', function() {
      console.log('[INFO] cordova.plugins.BackgroundGeolocation service has been started');
    });

    cordova.plugins.BackgroundGeolocation.on('stop', function() {
      console.log('[INFO] cordova.plugins.BackgroundGeolocation service has been stopped');
    });

    cordova.plugins.BackgroundGeolocation.on('authorization', function(status) {
      console.log('[INFO] cordova.plugins.BackgroundGeolocation authorization status: ' + status);
      if (status !== cordova.plugins.BackgroundGeolocation.AUTHORIZED) {
        // we need to set delay or otherwise alert may not be shown
        setTimeout(function() {
          var showSettings = confirm('App requires location tracking permission. Would you like to open app settings?');
          if (showSettings) {
            return cordova.plugins.BackgroundGeolocation.showAppSettings();
          }
        }, 1000);
      }
    });

    cordova.plugins.BackgroundGeolocation.on('background', function() {
      console.log('[INFO] App is in background');
      // you can also reconfigure service (changes will be applied immediately)
      cordova.plugins.BackgroundGeolocation.configure({ debug: true });
    });

    cordova.plugins.BackgroundGeolocation.on('foreground', function() {
      console.log('[INFO] App is in foreground');
      cordova.plugins.BackgroundGeolocation.configure({ debug: false });
    });

    cordova.plugins.BackgroundGeolocation.on('abort_requested', function() {
      console.log('[INFO] Server responded with 285 Updates Not Required');
      cordova.plugins.BackgroundGeolocation.stop();
      // Here we can decide whether we want stop the updates or not.
      // If you've configured the server to return 285, then it means the server does not require further update.
      // So the normal thing to do here would be to `cordova.plugins.BackgroundGeolocation.stop()`.
      // But you might be counting on it to receive location updates in the UI, so you could just reconfigure and set `url` to null.
    });

    cordova.plugins.BackgroundGeolocation.on('http_authorization', () => {
      console.log('[INFO] App needs to authorize the http requests');
    });

    cordova.plugins.BackgroundGeolocation.checkStatus(function(status) {
      console.log('[INFO] cordova.plugins.BackgroundGeolocation service is running', status.isRunning);
      console.log('[INFO] cordova.plugins.BackgroundGeolocation services enabled', status.locationServicesEnabled);
      console.log('[INFO] cordova.plugins.BackgroundGeolocation auth status: ' + status.authorization);

      // you don't need to check status before start (this is just the example)
      if (!status.isRunning) {
        cordova.plugins.BackgroundGeolocation.start(); //triggers start on start event
      }
    });

    // you can also just start without checking for status
    // cordova.plugins.BackgroundGeolocation.start();

    // Don't forget to remove listeners at some point!
    // cordova.plugins.BackgroundGeolocation.events.forEach(function(event) {
    //   return cordova.plugins.BackgroundGeolocation.removeAllListeners(event);
    // });
  }

}

Затем с app.component:

    import { Component, OnInit } from '@angular/core';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import {
      transition,
      trigger,
      query,
      style,
      animate,
      group,
      animateChild
    } from '@angular/animations';
    import { GeolocationService } from './_services/geolocation.service';

    declare const device;

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
      animations: [
        trigger('routeAnimation', [
          transition('* => *', [
            query(
              ':enter',
              [style({ opacity: 0 })],
              { optional: true }
            ),
            query(
              ':leave',
               [style({ opacity: 1 }), animate('0.3s', style({ opacity: 0 }))],
              { optional: true }
            ),
            query(
              ':enter',
              [style({ opacity: 0 }), animate('0.3s', style({ opacity: 1 }))],
              { optional: true }
            )
          ])
        ])
      ]
    })

    export class AppComponent implements OnInit{
      title = 'HLD Phlebotomist App';

  constructor(private geolocationService: GeolocationService) { }

      ngOnInit() { 
        document.addEventListener("deviceready", function() {
          this.geolocationService.startBackgroundGeolocation();
          alert(device.platform);
        }, false); 
      } 
    }

Однако, когда я запускаю это в эмуляторе Android, я получаю «Uncaught TypeError: Невозможно прочитать свойство startBackgroundGeolocation из undefined». Понятия не имею почему. Может кто-нибудь помочь мне понять структуру здесь? Я думаю, что моя проблема в том, что я не совсем понимаю, как «вызвать» плагин Cordova.

Ответы [ 2 ]

0 голосов
/ 27 мая 2019

Я пишу это здесь, потому что я изо всех сил пытался найти эти ответы в одном месте и собрал их воедино из различных постов в блоге и постов stackoverflow, каждый из которых казался неполным каким-то образом.

(1) Очень важно начальная загрузка

Источником постоянных ошибок и головной боли оказалось то, что в определенных условиях Angular и основное приложение будут загружены до того, как мобильное устройство (как Android, так и iOS) будет готово кобеспечить доступ к системным ресурсам, таким как камера.Это было чем-то, с чем я танцевал до тех пор, пока, наконец, добавление единого входа в качестве первого шага в нашем приложении не заставило меня столкнуться с проблемой более чем в 75% сценариев загрузки

Решение здесь довольно простое в main.tsвашего углового приложения добавьте javascript document.addEventListener, который ожидает, что cordova сообщит, что устройство готово, прежде чем начнется угловая загрузка.Тег script только тогда, когда мы включаем его в нашей переменной окружения.Это упростило тестирование функций non cordova с помощью ng serve в нашей тестовой среде.

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule).catch(e => console.error(e));
const bootstrapCordova = () => {
  /** Dynamically load cordova JS **/
  console.log('bootstrapped cordova');

  const script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = 'cordova.js';

  document.head.appendChild(script);

  if (script['readyState']) {
    // IE 2018 and earlier (?). They're migrating to using Chromium under the hood, so this may change
    script['onreadystatechange'] = () => {
      if (script['readyState'] === "loaded" || script['readyState'] === "complete") {
        document.addEventListener('deviceready', bootstrap, false);

      }
    };
  } else {
    // All other browsers
    document.addEventListener('deviceready', bootstrap, false);
  }
};
environment.cordova ? bootstrapCordova() : bootstrap();

(2) Распознавание типов

Поскольку cordova и ее плагины не нужныС самого начала, как часть Angular, нам нужно добавить наброски Cordova в наш проект Angular.Хотя можно написать код без этого, используя «оконные» функции особым образом, мы обнаружили, что важная типизация решает множество проблем.К счастью, кто-то предоставил машинописные наборы почти каждому ядру Cordova.Мы попытались просто установить эти типизации в файле типов, но обнаружили, что angular будет ворчать во время компиляции из-за наличия типов, но без библиотеки.Для записи, мы не чувствуем, что следующий метод должен работать, но снова и снова они были единственными повторяемыми шагами, которые стали угловатыми, чтобы прекратить ворчать.

Во-первых, мы поддерживаем наше угловое приложение в отдельном файловом пространстве от cordova.Затем мы записываем приложение в папку www, когда запускаем ng build --prod.это означает, что наше приложение cordova и наше угловое приложение имеют уникальный package.json для управления зависимостями npm.Для того чтобы получить доступ к наборам текста в angular, нам нужно добавить cordova и все плагины, которые мы используем, в package.json нашего углового проекта.

"cordova": "latest",
"cordova-plugin-camera": "latest",
"cordova-plugin-inappbrowser": "latest"

Второе - после того, как вы установили эти зависимости, нам нужно сгенерировать файл наборов для нашего проекта.Стоит отметить, что пакет "typings" устарел в npm в пользу "@types".однако мы не смогли выяснить, как достичь конечного результата, который мы хотели, с помощью "@types", поэтому на данный момент мы используем "typings"

npm install –g typings
typings search cordova
typings install dt~cordova --global --save

. Это создаст папку для наборов, где бы вы ни работаликоманда, поэтому мы рекомендуем сделать это в корне вашего углового проекта.Как только это будет сделано, добавьте файл типов в ваш tsconfig.app.json, и вы можете приступить к написанию кода.

"types": [
  "./typings/globals/cordova"
]

Третий - импорт на уровне файлов

В нашем исследовании мы видели многоспособов реализовать типизации на уровне кода, но только один работал в нашем проекте.Логика будет диктовать, что мы должны быть в состоянии сделать простое:

import {*} from 'typings/globals/cordova'

, и хотя наша идея была в порядке с этой сборкой ng --prod не было.вместо этого мы ссылаемся на файл наборов следующим образом:

/// <reference path="../../../../typings/globals/cordova/index.d.ts" />

, как только мы это сделали, мы смогли воспользоваться полной интеллигенцией в нашей IDE.

export class SplashComponent implements AfterViewInit, OnDestroy {
  private browser: InAppBrowser;
  private cordova: Cordova;

  constructor(private route: Router) {
    this.cordova = window['cordova']
this.browser = this.cordova.InAppBrowser;
  }

  ngAfterViewInit(){
      this.currentBrowser = this.browser.open('https://www.google.com', '_blank', 'location=yes');
}

}

(3) Сборка cordova

Если вы нигде не видели этого, знайте, что лучший способ справиться с остальными проблемами, с которыми вы сталкиваетесь при сборке в cordova, - это удалить свою платформу и добавить ее снова.

cordova platform rm android
cordova platform add android

Используя этот рабочий процесс, мы смогли устранить почти 100% ошибок времени выполнения, которые мы испытали с нашим приложением, и производительность нашего приложения взлетели до небес.

Надеемся, что если у вас возникли эти проблемы, высчитаю этот пост полезным, так как все, что я хотел, существовало.

Примечания:Правильный Angular способ обработки элементов «окна» этого кода - использовать токен инъекции. Я не включил это здесь, потому что это был длинный пост. Я могу обновить его позже, чтобы включить это.

0 голосов
/ 17 ноября 2018

Проблема заключалась в том, что Cordova CLI тянул версию 2.x плагина, но документация была для 3.x.В 2.x файл плагина был backgroundGeolocation.js, тогда как 3.x изменяет его на BackgroundGeolocation.js и добавляет файл BackgroundGeolocation.d.ts для поддержки реализаций TypeScript.Поскольку он чувствителен к регистру, он вызывался с неправильным именем и не получался.При добавлении @latest в мою команду cordova plugin add <plugin-name> была выбрана правильная версия, и она начала работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...