¿Comunicación entre Android Java y Phonegap Javascript?

81

Creo que es posible llamar a métodos Java desde (PhoneGap) Javascript.

¿¿Alguien sabe cómo hacer eso?? (Sé cómo hacerlo cambiando el código fuente de PhoneGap, pero lo evitaría)

zorglub76
fuente

Respuestas:

125

Finalmente lo hice funcionar.

  • Crea una clase con los métodos que quieras usar:

    public class MyClass {
      private WebView mAppView;
      private DroidGap mGap;
    
      public MyClass(DroidGap gap, WebView view)
      {
        mAppView = view;
        mGap = gap;
      }
    
      public String getTelephoneNumber(){
        TelephonyManager tm = 
          (TelephonyManager) mGap.getSystemService(Context.TELEPHONY_SERVICE);
        String number = tm.getLine1Number();
        return number;
      }
    }
    
  • En su actividad principal agregue una interfaz Javascript para esta clase:

    public class Main extends DroidGap
    {
        private MyClass mc;
    
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            super.init();
    
            mc = new MyClass(this, appView);
            appView.addJavascriptInterface(mc, "MyCls");
    
            super.loadUrl(getString(R.string.url));
        }
    }
    
  • En la ventana de llamada de Javascript.MyCls métodos:

    <script>
      $(function(){
        $("#phone").text("My telephone number is: " + 
                window.MyCls.getTelephoneNumber());
      });
    </script>
    

Nota:

Como se menciona en el comentario, para la versión 4.2 de Android y superior, agregue @JavascriptInterfaceal método al que desea acceder desde su página HTML. Referencia .

zorglub76
fuente
hmm, este ejemplo es genial, pero obtengo una excepción de puntero nulo en appView, parece ser nulo. ¿Dónde inicializa el objeto?
最 白 目
1
agregando super.init (); como @Karfield mencionado a continuación, solucionó la excepción de puntero nulo para mí.
Renato H.
8
¡Gran trabajo! Sugerencia: si desea comunicarse al revés (de Java a Javascript), use esto: mGap.sendJavascript ("window.myJavascriptFunction ('algún parámetro');");
aeldron
5
E / Consola web (2513): TypeError no detectado: Object [object Object] no tiene el método 'sendEmail' en file: ///android_asset/www/loginfile.js: 142 window.Mycls.sendEmail ("[email protected]" ); obtener Error en esta línea
Deepu Mandy
2
Probé este código para Android 4.2.2, me enfrenté a un problema similar a Deepu, es decir, Uncaught TypeError: Object [object Object] no tiene método 'getTelephoneNumber' en file: ///android_asset/www/app.js: 142. Después de un poco de depuración, descubrí que necesita agregar @JavascriptInterface para acceder a cualquier método al que desee acceder en javascript en el enlace
Akshay
14

addJavaScriptInterface(mc, "MyCls")sin Gap init()ed puede causar el aplastamiento de la aplicación, será mejor que agregue super.init()antesaddJavascriptInterface()

public class Main extends DroidGap
{
   private MyClass mc;

   @Override
   public void onCreate(Bundle savedInstanceState)
   {
       super.onCreate(savedInstanceState);

       super.init();

       mc = new MyClass(this, appView);
       appView.addJavascriptInterface(mc, "MyCls");

       super.loadUrl(getString(R.string.url));
   }
}
Karfield
fuente
9

PhoneGap tiene una API de complemento decente. Escribiría el complemento en Java implementando la interfaz IPlugin. La mayor parte de la magia está en la función execute ().

public interface IPlugin {

    /**
     * Executes the request and returns PluginResult.
     *
     * @param action        The action to execute.
     * @param args          JSONArry of arguments for the plugin.
     * @param callbackId    The callback id used when calling back into JavaScript.
     * @return              A PluginResult object with a status and message.
     */
    PluginResult execute(String action, JSONArray args, String callbackId);

        // ... more ...
}

La mejor manera de comenzar a escribir un complemento es escribiendo primero la API de JavaScript. Normalmente, comenzaría escribiendo una clase javascript personalizada y, en cada método de la clase javascript, ordenaría las variables y llamaría al complemento que desarrolló utilizando el método Phonegap.exec (). Aquí está la firma del método para su referencia.

/* src/com/phonegap/api/PluginManager.java */
/**
 * Receives a request for execution and fulfills it by finding the appropriate
 * Java class and calling it's execute method.
 *
 * PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
 * string is returned that will indicate if any errors have occurred when trying to find
 * or execute the class denoted by the clazz argument.
 *
 * @param service       String containing the service to run
 * @param action        String containt the action that the class is supposed to perform. This is
 *                      passed to the plugin execute method and it is up to the plugin developer
 *                      how to deal with it.
 * @param callbackId    String containing the id of the callback that is execute in JavaScript if
 *                      this is an async plugin call.
 * @param args          An Array literal string containing any arguments needed in the
 *                      plugin execute method.
 * @param async         Boolean indicating whether the calling JavaScript code is expecting an
 *                      immediate return value. If true, either PhoneGap.callbackSuccess(...) or
 *                      PhoneGap.callbackError(...) is called once the plugin code has executed.
 *
 * @return              JSON encoded string with a response message and status.
 */
@SuppressWarnings("unchecked")
public String exec(final String service, final String action,
    final String callbackId, final String jsonArgs,
    final boolean async)

También debe registrar el complemento. Para ello, agregue el código de registro en la parte inferior de su biblioteca javascript personalizada.

En el siguiente ejemplo, el autor definió una clase de JavaScript BarcodeScanner y la registra utilizando el método addConstructor.

En addConstructor se llevan a cabo dos pasos:

  1. Cree una nueva instancia de BarcodeScanner en javascript y regístrela. Esto es accesible en javascript como window.plugins.barcodeScanner

  2. Registra la clase de complemento personalizada con un nombre de servicio. Este nombre de servicio se pasa como primer argumento a PhoneGap.exec para que PhoneGap pueda crear una instancia de la clase de complemento java y llamar al método execute () en ella.

Código de registro de muestra:

PhoneGap.addConstructor(function() {
    /* The following registers an instance of BarcodeScanner in window.plugins.barcodeScanner */
    PhoneGap.addPlugin('barcodeScanner', new BarcodeScanner());

    /* The following associates a service name BarcodeScanner with a class com.beetight.barcodescanner.BarcodeScanner */
    /* The service name is the first argument passed into PhoneGap.exec */
    PluginManager.addService("BarcodeScanner","com.beetight.barcodescanner.BarcodeScanner");
});
Chui Tey
fuente
¿Para qué versión de phonegap es esta muestra? Creo que estás hablando por debajo de 2.0. ¿Derecho?
Anas Azeem
6

una forma más simple:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.init(); 
    super.appView.getSettings().setJavaScriptEnabled(true);
    super.appView.addJavascriptInterface(this, "MyCls");
    super.loadUrl("file:///android_asset/www/login.html");
}
Heladio Benicio
fuente
5

Si alguien obtiene una excepción nullPointer usando el código anterior, primero haga super.oncreate () y luego super..init ()

super.onCreate(savedInstanceState);
super.init();

Encontré esta solución aquí: Phonegap Google Group

Muchas gracias a @ zorglub76 por la solución ....

Dhairya Vora
fuente
0

La comunicación de JavaScript a nativo se logra anulando la función de solicitud de JavaScript en el código nativo de Android y el mensaje que se transmite es muy parecido al que se usa en iOS. Solíamos usar WebView.addJavascriptInterface para agregar objetos Java directamente al sandbox de JavaScript, pero eso estaba causando que algunos dispositivos fallaran con Android 2.3. Para llamar a JavaScript desde el nativo, actualmente usamos WebView.loadUrl (”javascript:…”) ​​pero eso tiene algunos problemas, por lo que pronto pasaremos a sondear una cola de mensajes Java que llama a un servidor HTTP local a través de una conexión XHR de larga duración.

Descripción por aquí

Bodil
fuente