When I attempt to use "ng --build" to build my project so that I can then run "cordova build android" and
"cordova emulate android" and test my app, the build fails because BackgroundGeolocation.js can't seem to figure out where cordova/exec and cordova/channel are.
cordova -v): 8.1.2 ([email protected])cordova platform ls):
I wouldn't call it a bug, more likely something I am doing wrong, but there is little to no documentation and/or community topics on how to use 3rd party Cordova plugins with vanilla Angular (almost everything mentions Ionic to some degree, which I am not using). As a result, I have no idea if it's a bug or not.
No error - Cordova object should be wrapped in exec and channel and work as expected.
Errors appear stating that the module cannot be found
Unsure of how to fix
Cannot build app without getting around this. I am simply trying to add this plugin to my existing project
allen@tornado:~/scripts/lysi/hld-mileage-tracker$ ng build --prod
Date: 2018-11-16T03:13:17.338Z
Hash: 2b236b3e85e64b1333ef
Time: 21951ms
chunk {0} runtime.ec2944dd8b20ec099bf3.js (runtime) 1.41 kB [entry] [rendered]
chunk {1} main.ce39aa839131f9d29c6a.js (main) 779 kB [initial] [rendered]
chunk {2} polyfills.d1c7bf4a2ae7c3435f95.js (polyfills) 37.5 kB [initial] [rendered]
chunk {3} styles.254a64e6ae38a8bf3664.css (styles) 64.6 kB [initial] [rendered]
ERROR in ./node_modules/cordova-plugin-mauron85-background-geolocation/www/BackgroundGeolocation.js
Module not found: Error: Can't resolve 'cordova/channel' in '/home/allen/projects/mileage-tracker/node_modules/cordova-plugin-mauron85-background-geolocation/www'
ERROR in ./node_modules/cordova-plugin-mauron85-background-geolocation/www/BackgroundGeolocation.js
Module not found: Error: Can't resolve 'cordova/exec' in '/home/allen/projects/mileage-tracker/node_modules/cordova-plugin-mauron85-background-geolocation/www'
I am also having this issue.

I finally figured this one out - the BackgroundaGeolocation.js file needs this on lines 12-13:
var exec = cordova.require('cordova/exec');
var channel = cordova.require('cordova/channel');
...instead of the existing code, which is this:
var exec = require('cordova/exec');
var channel = require('cordova/channel');
However, @mauron85 advised me in another issue that I opened that the version installed by the Cordova CLI (which I think comes from NPM or something) has bugs that have been fixed in the master branch of the git repo for it. He suggested installing via git in order to get those changes, so it's possible this may have been fixed too.
Update: I checked and the version on git does not have cordova.require in it and simply has require. @ShafiqEssani if you're using Angular as well, you might want to try this workaround for the issue to see if it works for you.
This issue should not be closed as the problem is still present.
This does not only concern vanilla Angular project but Ionic ones also (since it's based on Angular).
Having to edit the plugin sources is NOT a solution.
If your app is built in CI, it won't work.
If your app is developped by multiple developpers, they all will have to do it.
etc..
I
Leaving open, but cannot reproduce this.
Is there any relevant info in cordova docs?
Rephrasing my question. Is this related to Angular/Ionic only or also to plain Cordova?
Edit: Official cordova plugins are using same sematics.
https://github.com/apache/cordova-plugin-battery-status/blob/master/www/battery.js
It is related to Angular/Ionic and your types definition.
When you import the BackgroundGeolocation object :
import BackgroundGeolocation from 'cordova-plugin-mauron85-background-geolocation';
The typescript compiler tries to compile node_modules/cordova-plugin-mauron85-background-geolocation/www/BackgroundGeolocation.js, which fails because the requires in
var exec = require('cordova/exec');
var channel = require('cordova/channel');
cannot be resolved (they are resolved only inside the cordova environnement).
@mauron85 What you can do to solve this is to export the BackgroundGeolocoationPlugin interface from your types file :
export interface BackgroundGeolocationPlugin {
// stuff //
}
so Angular/Ionic users can import it and do :
import { BackgroundGeolocationPlugin } from 'cordova-plugin-mauron85-background-geolocation';
declare const BackgroundGeolocation: BackgroundGeolocationPlugin;
whenever they want to use your plugin.
I tested it on my current app and it works like a charm.
@TomDemulierChevret thank you for explanation. Can't we just add some kind of ts-ignore for those two lines? How are other plugins (or @types definitions) doing this.
If we don't find better solution then we can go with your proposal.
What I know for sure, I'm for sure NOT going to replace require with cordova.require.
You're welcome.
I'm not sure for other plugins, I haven't written any @types definition, only used them.
For cordova plugins, I usually use the @ionic/native wrappers around them which provide an Angular service.
I'm not sure the ts-ignore approach is the right way, the typescript compiler shouldn't event try to compile plugins files since it's the job of cordova to package them with the app.
I can live with @TomDemulierChevret suggestion to export the plugin interface.
I also tried to use /// <reference types="..." but I couldn't make it work...
Most plugins I tired do not have types :-((, the one that does work for me with the types and might provide a working example is the cordova-plugin-camera.
I'm using it with /// <reference types="cordova-plugin-camera" />
Just FYI, my sub-optimal workaround only works for Android and iOS emulation. When browser emulation is used, an error is thrown on the lines where I added cordova.require because "cordova" can't be resolved. I'm assuming it has something to do with the files being read before the device is ready, before cordova is instantiated or whatever. @TomDemulierChevret, do you happen to have a more specific example of the testing you did? I tried adding what you had there to my project and it still had no idea what cordova was with respect to the plugin files. I tried defining cordova via "declare var cordova" but that simply changed the error from a "not defined" error to an "undefined" error, which wasn't necessarily surprising - I was just grasping at straws there.
@allensutton With the current version, I just use
declare const BackgroundGeolocation: any;
in the file where I want to use the plugin. It will build but you won't benefit from types (and therefore error detection, autocompletion, etc).
If my proposal goes through, you will just have to use this instead :
declare const BackgroundGeolocation: BackgroundGeolocationPlugin;
The problem is you shouldn't be doing import BackgroundGeolocation from 'cordova-plugin-mauron85-background-geolocation'; to use the plugin in Angular.
To use the types you should add this on the first line of the file where you are going to use the plugin.
/// <reference types="cordova-plugin-mauron85-background-geolocation" />
But looks like the exports on the types file makes it to not work, I've sent a PR that removes them and now I can use BackgroundGeolocation. in my .ts file and it shows autocompletion
https://github.com/mauron85/cordova-plugin-background-geolocation/pull/523
Now plugin is failing no matter if you put cordova.require or just require.
It will give you the error Error: ./node_modules/cordova-plugin-mauron85-background-geolocation/www/BackgroundGeolocation.js Module not
found: Error: Can't resolve 'cordova/channel
Guys, just small warning here. I'm not going to merge any workaround targeting ionic only and making it worse for non ionic users (like removing exports).
I truly want to help, but I've never used ionic myself. Maybe you can ask ionic team for help. Because this plugin is following cordova plugin spec.
If you check all Cordova core plugins, none of them use exports on the types. Not sure why do you say this is for Ionic, but it's not, I already explained in the PR.
Not sure how you use typescript, but the exports are not needed.
@jcesarmobile I explained the reasoning directly in your PR. https://github.com/mauron85/cordova-plugin-background-geolocation/pull/523
If you check all Cordova core plugins, none of them use exports on the types.
Can you send me one, that's using typescript definitions directly (not via typing/DefinitelyTyped). I'll check it out.
All core plugins ship with the definitions nowadays https://github.com/apache/cordova-plugin-camera/blob/master/types/index.d.ts
Thanks. Btw I found this article about adding cordova plugin to ionic2. https://www.techiediaries.com/mobiledev/ionic2-typescript-cannot-find-name-cordova/
Basically it suggest adding dt~cordova typings. Would it help here too?
No, that's for when the plugin is added to cordova object, your plugin uses BackgroundGeolocation object directly.
Also doing that just allows to use the plugin, for using yours people can just do declare const BackgroundGeolocation: any;.
That will allow to use the plugin, but won't benefit from the types (error detection, autocompletion, etc.) as already noted by @TomDemulierChevret
ok your persistence made me installing ionic. Btw I cannot replicate this in plain cordova typescript project. I've made example of such project https://github.com/mauron85/cordova-typescript
Just installed ionic. And only I can say, that ionic is not supporting imports of typed cordova plugins.
Not sure why cordova-plugin-camera works. But I guess, it only works with import { Camera, CameraOptions } from '@ionic-native/camera'; and not with import Camera from 'cordova-plugin-camera'; Somebody can confirm this?
I can only suggest you to open issue there, asking to support cordova plugins without workarounds.
EDIT: I've failed with import Camera from 'cordova-plugin-camera';
node_modules/cordova-plugin-camera/types/index.d.ts' is not a module.
So different error, but same outcome. You simply cannot use typed cordova plugins with ionic, without ionic wrapper or any other workaround mentioned here.
I'm not using ionic but pure angular with cordova and have this issue when trying to import this library.
As I wrote, I'm using triple slash to get camera typings and it works good.
I can instruct you how to build my code so you can see the error.
@HarelM can you prepare basic example app?
Camera plugin (or any core plugin) works if you use the Triple-Slash Directive instead of import. The way the core plugins are built don't allow import, nor in an Ionic project, not in your sample project, it's just how the types are built, they can only be used like this /// <reference types="cordova-plugin-camera" />
You built your types in a different way that don't allow the Triple-Slash Directive, but allow the import, I'm ok with that.
The problem here is not related to Ionic nor Angular, it's related to web bundlers. (In this case webpack, that is used by Angular, not sure if others are also affected)
When using import as in your example, bundlers will look for require keyword in the package you imported, and you have require keyword in the .js files for making cordova exec work, but webpack just sees the require and goes crazy.
I suppose you can exclude the .js files so webpack doesn't analyze them, but not sure how.
The problem here is not related to Ionic nor Angular, it's related to web bundlers.
probably true, I don't know as I never studied what ionic is made of (I really don't care about ionic nor angular). I said ionic, meaning some module (bundler, ... whatever) ionic is using.
The problem here is not related to Ionic nor Angular, it's related to web bundlers.
I'll try to add webpack to my example app.
Also I've doubts that /// <reference types="cordova-plugin-camera" /> will work will plugin provided typings, but not going to investigate as I spent way to much time that I wanted.
In your sample project I installed camera plugin, added /// <reference types="cordova-plugin-camera" /> on top of the .ts and now I can use camera plugin and VS Code have autocomplete for navigator.camera, see the screenshot.

If I click on getPicture it takes me to the plugin types file.
Not sure why you don't think it will work, but it works.
Not sure why you don't think it will work, but it works.
I should probably edit my comment. It works when not importing as module, but rather using "exported" global window.navigator.
No, using the triple slash I can use navigator.camera without creating it as global, it just works and have autocomplete on VS Code.
Without the triple slash you can use it with the global and without benefiting from the autocomplete
Below is the file that shows the issue - without ionic.
To see the error run:
npm install
npm run build -- --prod
geolocation-import-issue.zip
This is as minimal as possible, I think. The code that import this module is in src/app/app.component.ts
The only workaround possible is @TomDemulierChevret's.
It basically means relying on global variable BackgroundGelocation (import from .. in current form is not possible). After change you still will be importing but not declared var, but rather type def. It's bit complicated to explain.
I'll try if webpack is affected with this issue too and if yes then I can do the change.
@mauron85 my zip contains angular example which uses webpack. Feel free to test with it. Let me know if you need any help.
I've just published version 3.0.0-alpha.50. Following @TomDemulierChevret's advice, I've added export interface BackgroundGeolocationPlugin. It will fix this issue and ionic users can still benefit from provided types. All kudos to @TomDemulierChevret.
Example:
import { Injectable, NgZone } from '@angular/core';
// This is important!
import { BackgroundGeolocationPlugin } from 'cordova-plugin-mauron85-background-geolocation';
// This is important!
declare const BackgroundGeolocation: BackgroundGeolocationPlugin;
@Injectable()
export class LocationTracker {
public watch: any;
public lat = 0;
public lng = 0;
constructor(public zone: NgZone) {
}
startTracking() {
// Background Tracking
const config = {
desiredAccuracy: 0,
stationaryRadius: 20,
distanceFilter: 10,
debug: true,
interval: 2000
};
BackgroundGeolocation.configure(config);
// Turn ON the background-geolocation system.
BackgroundGeolocation.start();
}
stopTracking() {
BackgroundGeolocation.stop();
}
}
Works great! Thanks! I believe this issue can be closed, assuming this info is added to documentation.

I installed the latest version and rebuilt my app - the plugin now works as-is with no workarounds, no errors at all, and background geolocation works as it did before. Thanks everyone!
Most helpful comment
I've just published version 3.0.0-alpha.50. Following @TomDemulierChevret's advice, I've added
export interface BackgroundGeolocationPlugin. It will fix this issue and ionic users can still benefit from provided types. All kudos to @TomDemulierChevret.Example: