Gustavo Conde
Gustavo Conde

Reputation: 977

Ionic build cannot find module error. How to import Android plugin?

I'm trying to develop an Android Plugin to use in an Ionic app.

I created the app with a starter project already provided by Ionic using ionic start myApp tabs.

I have also created, in a different folder, my plugin, that contains the following files.

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="location-plugin" version="0.0.1">
<name>GSLocationManager</name>
<description>Location Plugin</description>
<license>MIT</license>
<keywords>cordova,device,sensors,location</keywords>

<js-module name="LocationManager" src="www/LocationManager.js">
    <clobbers target="LocationManager" />
</js-module>

<engines>
    <engine name="cordova" version=">=3.6.0"></engine>
</engines>

<platform name="android">
  <preference name="GOOGLE_PLAY_SERVICES_VERSION" default="11+"/>
  <preference name="ANDROID_SUPPORT_LIBRARY_VERSION" default="26+"/>
  <preference name="ICON" default="@mipmap/icon" />
  <preference name="SMALL_ICON" default="@mipmap/icon" />
  <preference name="ACCOUNT_NAME" default="@string/app_name" />
  <preference name="ACCOUNT_LABEL" default="@string/app_name" />
  <preference name="ACCOUNT_TYPE" default="$PACKAGE_NAME.account" />
  <preference name="CONTENT_AUTHORITY" default="$PACKAGE_NAME" />

  <framework src="com.google.android.gms:play-services-location:$GOOGLE_PLAY_SERVICES_VERSION" />
  <framework src="com.android.support:support-v4:$ANDROID_SUPPORT_LIBRARY_VERSION" />
  <framework src="com.android.support:appcompat-v7:$ANDROID_SUPPORT_LIBRARY_VERSION" />
  <!-- <framework src="android/dependencies.gradle" custom="true" type="gradleReference"/> -->

  <source-file src="path/to/locationmanager/GSLocationManager.java"
               target-dir="path/to/locationmanager"></source-file>

  <config-file target="AndroidManifest.xml" parent="/manifest">
     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.hardware.location" />
  </config-file>

  <config-file target="res/xml/config.xml" parent="/*">
      <feature name="GSLocationManager">
          <param name="android-package" value="android.package.locationmanager.GSLocationManager" />
      </feature>
  </config-file>
</platform>

locationManager.js

var GSLocationManager = {
  getCurrentLocation: function(success, failure) {
    exec(success, failure, 'GSLocationManager', 'getCurrentLocation', []);
  }
}

module.exports = GSLocationManager;

GSLocationManager.java

package android.package.locationmanager;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CordovaPlugin;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;

import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;

public class GSLocationManager extends CordovaPlugin {

    private JSONObject data = new JSONObject();

    // at the initialize function, we can configure the tools we want to use later, like the sensors
    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);

    }

    // safety unregistering from the events if the application stops somehow
    @Override
    public void onDestroy() {

    }

    // this is the main part of the plugin, we have to handle all of the actions sent from the js
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if ("getCurrentLocation".equals(action)) {
            Location location = getCurrentLocation();
            JSONObject json = new JSONObject();
            json.put("latitude", location.getLatitude());
            json.put("longitude", location.getLongitude());
            callbackContext.success(json);
            return true;
        }
        return false;  // Returning false results in a "MethodNotFound" error.
    }

    @SuppressLint("MissingPermission")
    private Location getCurrentLocation() {
        LocationManager locationManager = (LocationManager) cordova.getActivity().getApplicationContext().getSystemService(Context.LOCATION_SERVICE);

        Location lastKnownGPSLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        return lastKnownGPSLocation;
    }
}

Then I created a package.json for my plugin usign plugman And after that, added my android plugin to my Ionic project by doing ionic cordova plugin add path/to/my/plugin

But I cannot seem to be able to import my plugin to app.module.ts using import { GSLocationManager } from 'globespinning-location-plugin' I try to build but CLI says ERROR in src/app/app.module.ts(12,31): error TS2307: Cannot find module 'globespinning-location-plugin'.

Any idea where the error is? How should I import a plugin created by me, and referenced from a local folder? I want to be able to call GSLocationManager.getCurrentLocation() inside my ionic app.

Upvotes: 5

Views: 1696

Answers (4)

Gustavo Conde
Gustavo Conde

Reputation: 977

What @Tachyon and @SeunBincom answer was helpful, but the problem was with my plugin.xml file. With the help of Android Studio I was able to debug it and finally got it working.

The xml ended up like this:

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
        id="globespinning-location-plugin" version="0.0.1">
    <name>LocationManager</name>
    <description>Globespinning Location Plugin</description>
    <license>MIT</license>
    <keywords>cordova,device,sensors,location</keywords>

    <js-module name="LocationManager" src="www/locationManager.js">
        <clobbers target="LocationManager" />
    </js-module>

    <platform name="android">
      <preference name="GOOGLE_PLAY_SERVICES_VERSION" default="11+"/>
      <preference name="ANDROID_SUPPORT_LIBRARY_VERSION" default="26+"/>
      <preference name="ICON" default="@mipmap/icon" />
      <preference name="SMALL_ICON" default="@mipmap/icon" />
      <preference name="ACCOUNT_NAME" default="@string/app_name" />
      <preference name="ACCOUNT_LABEL" default="@string/app_name" />
      <preference name="ACCOUNT_TYPE" default="$PACKAGE_NAME.account" />
      <preference name="CONTENT_AUTHORITY" default="$PACKAGE_NAME" />

      <framework src="com.google.android.gms:play-services-location:$GOOGLE_PLAY_SERVICES_VERSION" />
      <framework src="com.android.support:support-v4:$ANDROID_SUPPORT_LIBRARY_VERSION" />
      <framework src="com.android.support:appcompat-v7:$ANDROID_SUPPORT_LIBRARY_VERSION" />
      <framework src="src/android/dependencies.gradle" custom="true" type="gradleReference"/>

      <source-file src="src/android/com/globespinning/ionic/locationmanager/GSLocationManager.java"
                   target-dir="src/com/globespinning/ionic/locationmanager"></source-file>

      <config-file target="AndroidManifest.xml" parent="/manifest">
         <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
         <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
         <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
         <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
         <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
         <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
         <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
         <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
         <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
         <uses-permission android:name="android.permission.INTERNET" />
         <uses-permission android:name="android.permission.WAKE_LOCK" />
         <uses-permission android:name="android.hardware.location" />
      </config-file>

      <config-file target="res/xml/config.xml" parent="/*">
          <feature name="LocationManager">
              <param name="android-package" value="com.globespinning.ionic.locationmanager.GSLocationManager" />
          </feature>
      </config-file>
    </platform>
</plugin>

Upvotes: 1

Triple0t
Triple0t

Reputation: 444

in addition to @tachyon answer, here are some stuff to note.

  • You need to create a declaration (.d.ts) file for your plugin js before you can use the import * from * syntax. it is not required in this case tho.
  • check if you have accurately defined the namespace for the js methods. yours is here <clobbers target="LocationManager" />

Therefore, here is how to implement such in your case;

In the .TS File you wish to execute the function

// at the top of the file. after all the import statements
import { Component } from '@angular/core';  // i'm using this as an example.
import { Platform } from '@ionic/angular';  // you need the platform

declare var LocationManager;
...
constructor(
private platform: Platform
){
  this.platform.ready().then(() => {
   // we will make use of the plugin here
   console.log('LocationManager: ', LocationManager); // we can check if it exist by logging it out to the console
   if (LocationManager) {
      LocationManager.GSLocationManager.getCurrentLocation(
         success => {
            console.log('LocationManager: Got Location: ', success);
         }, error => {
            console.log('LocationManager: Err Getting Location: ', error);
         }
      );
    }
  });
}

you can read more here: How to use a plugin without using ionic-native?, https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html

Upvotes: 1

Tachyon
Tachyon

Reputation: 2411

You want to go ahead and run ionic cordova plugin add "folder path of your custom plugin" after that in the .ts file you want to use it in you want to declare the following, declare var myPlugin: any;

Once you have declared the plugin you can go ahead and use it as follows:

myPlugin.myFuntion((data) => {
        console.log(data);
},(err) => {
        console.log(err);
});

So in your case you'd use the following:

declare var GSLocationManager: any;

....

GSLocationManager.getCurrentLocation().then((data) => {});

Upvotes: 1

bb1
bb1

Reputation: 161

If the import fails this could be very likely related to your tsconfig.json or your angular module (app.module.ts). Check if the file in included and not.

You only posted your Java-Files. Are you sure this runs on a browser?

Upvotes: -1

Related Questions