首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在没有离子的情况下使用Angular调用Cordova插件

如何在没有离子的情况下使用Angular调用Cordova插件
EN

Stack Overflow用户
提问于 2018-11-15 07:20:29
回答 2查看 3.6K关注 0票数 0

我在Angular 6中构建了一个PWA,打算将Google Maps API用于地理定位。然而,我很快意识到,PWA中的地理位置服务只有在用户与UI交互以故意请求他们的位置时才能工作。然而,我的应用程序应该在用户开车时在后台跟踪用户的位置。因此,当他们锁定屏幕或转到不同的应用程序时,它仍然应该跟踪他们。需要指出的是,这是一个私人应用程序,用户完全知道他们正在被跟踪。因此,我使用Cordova将PWA转换为混合应用程序。到目前为止,一切都可以使用我已经拥有的东西(仿真很好,等等),但我似乎想不出如何添加地理位置部分。我已经安装了this插件,它似乎已经安装并可用。我见过的所有示例都使用Ionic (此时我不需要),并且用于用户单击按钮来获取他们的位置的场景,但我需要它,因为地理位置的东西在服务中,并在他们登录后开始在后台运行。我似乎找不到能说明如何做到这一点的东西。这是我想我应该做的:

(这并不完整,我只是在这里粘贴了来自GitHub的示例代码,并打算在我知道它实际上被调用时用“东西”填充它)

_services/geolocation.service.ts:

代码语言:javascript
复制
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:

代码语言:javascript
复制
    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); 
      } 
    }

然而,当我在安卓模拟器中运行它时,我得到了“未捕获TypeError:无法读取未定义的属性'startBackgroundGeolocation‘”。不知道为什么。有人能帮我理解一下这里的结构吗?我想我的问题是我不完全理解如何“调用”Cordova插件。

EN

回答 2

Stack Overflow用户

发布于 2019-05-28 01:37:32

我之所以在这里写这篇文章,是因为我努力在一个地方找到这些答案,并从各种博客帖子和stackoverflow帖子中将它们拼凑在一起,所有这些似乎都不完整。

(1)非常重要的自举

在某些情况下,Angular和核心应用程序会在移动设备(包括安卓和iOS)准备好提供对相机等系统资源的访问之前启动。这是我一直在考虑的事情,直到最终在我们的应用程序中添加SSO作为第一步,这让我在超过75%的加载场景中都遇到了这个问题

这里的解决方案非常简单,在angular应用程序的main.ts中添加一个javascript document.addEventListener,它在引导angular之前等待cordova说设备已经准备好了。

代码语言:javascript
复制
document.addEventListener('deviceready', bootstrap, false);

我们实际上更进一步,添加了一个条件块,仅当我们在环境变量中打开cordova脚本标记时才注入它。这使得在我们的测试环境中使用ng serve测试非cordova特性变得更容易。

代码语言:javascript
复制
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插件都有人为其贡献了typescript类型。我们尝试在一个类型文件中安装这些类型,但发现angular在编译时会抱怨有类型但没有库。根据记录,我们不认为下面的方法应该有效,但一次又一次,它们是唯一可复制的步骤,可以停止抱怨。

首先,当我们运行ng build --prod时,我们在cordova之外的一个单独的文件空间中维护我们的angular应用程序,然后将应用程序写入www文件夹。这意味着我们的cordova应用程序和angular应用程序都有一个独特的package.json来管理npm依赖项。为了在angular中访问cordova类型,我们需要将cordova和我们正在使用的所有插件添加到angular项目的package.json中。

代码语言:javascript
复制
"cordova": "latest",
"cordova-plugin-camera": "latest",
"cordova-plugin-inappbrowser": "latest"

第二,一旦你安装了这些依赖项,我们需要为我们的项目生成一个类型文件。值得注意的是,“类型”包在npm中被弃用,取而代之的是"@types“。然而,我们无法弄清楚如何使用"@types“来实现我们想要的最终结果,所以现在我们使用”类型“。

代码语言:javascript
复制
npm install –g typings
typings search cordova
typings install dt~cordova --global --save

这将在您运行该命令的位置生成一个typings文件夹,因此我们建议在您的angular项目的根目录中执行此操作。完成后,将类型文件添加到您的tsconfig.app.json中,就可以开始编码了。

代码语言:javascript
复制
"types": [
  "./typings/globals/cordova"
]

第三级文件级导入

在我们的研究中,我们看到了许多在代码级别实现类型的方法,但在我们的项目中只有一种方法有效。逻辑将规定我们应该能够做一个简单的:

代码语言:javascript
复制
import {*} from 'typings/globals/cordova'

虽然我们的ide可以很好地处理这个ng构建--prod却不行。取而代之的是,我们以以下方式引用类型文件:

代码语言:javascript
复制
/// <reference path="../../../../typings/globals/cordova/index.d.ts" />

一旦我们做到了这一点,我们就能够从IDE中的完整智能感知中获益。

代码语言:javascript
复制
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中遇到的任何剩余问题的最好方法就是删除您的平台并重新添加它。

代码语言:javascript
复制
cordova platform rm android
cordova platform add android

使用这个工作流程,我们能够消除几乎100%的运行时错误,我们的应用程序的性能也直线上升。

希望如果你有这些问题,你会发现这篇文章很有帮助,因为它是我希望存在的所有东西。

注意:处理此代码的“窗口”元素的正确角度方法是使用注入标记。我没有在这里包含它,因为这是一个很长的帖子。我稍后可能会更新它,以包括这一点。

票数 5
EN

Stack Overflow用户

发布于 2018-11-17 22:56:34

这里的问题是Cordova CLI提取的是2.x版的插件,但文档是3.x版的。在2.x中,插件文件是backgroundGeolocation.js,而3.x将其更改为BackgroundGeolocation.js,并添加了一个BackgroundGeolocation.d.ts文件来支持TypeScript实现。因为它是区分大小写的,所以它被错误的名称调用,并且失败了。将@latest添加到我的cordova plugin add <plugin-name>命令中会拉下正确的版本,然后它就开始工作了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53310236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档