1

This question seems like duplicate but I've tried with all the solutions in SO but nothing worked for me.

My question is, I want to call the javascript function from cordova java file (Which is extended from CordovaPlugin). For this I've checked reference 1, reference 2, reference 3 and many more from online but nothing worked for me

My code

Sample.js

function sendVoice() {

try {
  ApiAIPlugin.requestVoice(
    {}, // empty for simple requests, some optional parameters can be here
    function (response) {
        // place your result processing here
        alert(JSON.stringify(response));
    },
    function (error) {
        // place your error processing here
        alert(error);
    });
  } catch (e) {
    alert(e);
  }
}

Sample.java

WebView webView = new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
webView.loadUrl("javascript.sendVoice();");

I tried with simple alert in java file as below

WebView webView = new WebView(MainActivity.this);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
webView.loadUrl("javascript:alert('hello')");

i'm able to watch the above alert, But I'm unable to access the javascript function from java file. Any one have idea about this

Update

VoiceBotPlugin.java

package VoiceBotPlugin;

public class VoiceBotPlugin extends CordovaPlugin {

Context context;
boolean recordAudio = false;


float newX, newY, dX, dY, screenHight, screenWidth;
ImageView img;
int lastAction;
WebView webView;
public String  sJava = "String from JAVA";

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    if (action.equals("coolMethod")) {
        String message = args.getString(0);
        this.coolMethod(message, callbackContext);

        this.webView.loadUrl("javascript:sendVoice();");
        //this.webView.evaluateJavascript("sendVoice();", null);

        context = this.cordova.getActivity();
        ((Activity) context).runOnUiThread(new Runnable() {
              @Override
              public void run() {
                createFlotingActionButton();
              }
        });

        return true;
    }
    return false;
}

private void coolMethod(String message, CallbackContext callbackContext) {
    if (message != null && message.length() > 0) {
        callbackContext.success(message);
    } else {
        callbackContext.error("Expected one non-empty string argument.");
    }
}


private void createFlotingActionButton(){

      FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
      params.topMargin = 0;
      params.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;

      img = new ImageView(context);
      setImage(img, "icon_record");

      cordova.getActivity().addContentView(img, params);

      DisplayMetrics displaymetrics = new DisplayMetrics();
      ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
      screenHight = displaymetrics.heightPixels;
      screenWidth = displaymetrics.widthPixels;

      img.setOnTouchListener(new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {


             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:

                     dX = img.getX() - event.getRawX();
                     dY = img.getY() - event.getRawY();
                     lastAction = MotionEvent.ACTION_DOWN;
                     break;

                 case MotionEvent.ACTION_MOVE:

                     newX = event.getRawX() + dX;
                     newY = event.getRawY() + dY;

                     // check if the view out of screen
                     if ((newX <= 0 || newX >= screenWidth-img.getWidth()) || (newY <= 0 || newY >= screenHight-img.getHeight()))
                     {
                         lastAction = MotionEvent.ACTION_MOVE;
                         break;
                     }

                     img.setX(newX);
                     img.setY(newY);

                     lastAction = MotionEvent.ACTION_MOVE;

                     break;

                 case MotionEvent.ACTION_UP:
                     if (lastAction == MotionEvent.ACTION_DOWN) {
                        if (recordAudio) {
                            setImage(img, "icon_record");
                            recordAudio = false;
                        } else {
                            setImage(img, "icon_mute");
                            recordAudio = true;

                            //callJavaScriptFunction();

                        }
                    }
                     break;

                 default:
                     return false;
             }
             return true;

         }
      });

  }

  private void setImage(ImageView imageView, String iconName){
      Resources activityRes = cordova.getActivity().getResources();
      int backResId = activityRes.getIdentifier(iconName, "drawable", cordova.getActivity().getPackageName());
      Drawable backIcon = activityRes.getDrawable(backResId);
      if (Build.VERSION.SDK_INT >= 16)
        imageView.setBackground(null);
      else
        imageView.setBackgroundDrawable(null);

      imageView.setImageDrawable(backIcon);
  }

  private void callJavaScriptFunction(){
    WebView webView = new WebView(context);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebChromeClient(new WebChromeClient());
    this.webView.loadUrl("javascript:sendVoice();");

    /*String js = String.format("window.sendVoice();", null);
    webView.sendJavascript(js);*/
  }

}

2 Answers 2

6

You can try something like this - cordova and webView are implicitly defined by the CordovaPlugin class:

public class MyPlugin extends CordovaPlugin {

    @Override
    public boolean execute(String action, JSONArray args,
                           CallbackContext callbackContext) throws JSONException {
        if(action.equals("foo")){
            executeGlobalJavascript("alert('hello')");
        }
        return true;
    }                       

    private void executeGlobalJavascript(final String jsString){
        cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                webView.loadUrl("javascript:" + jsString);
            }
        });
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hi DaveAlden, thank you for your reply. I've tried with your solution. It's working perfectly for executeGlobalJavascript("alert('hello')"); but it's not working when i'm trying for executeGlobalJavascript("sendVoice()");. While using sendVoice() getting Uncaught ReferenceError: sendVoice is not defined at <anonymous>:1:1
is Sample.js being loaded and is sendVoice() therefore actually defined? Try connecting Chrome Dev Tools to the webview and executing sendVoice() manually from the console.
Yes Sample.js was loaded and sendVoice() is in that only. I've checked sendVoice() in Chrome Dev, getting error like Uncaught ReferenceError: sendVoice is not defined. For other details please check VoiceBotPlugin.java (line 60 and 190 to 197) and VoiceBotPlugin.js
The problem is that you've defined sendVoice() within your plugin's JS component. Cordova will wrap this such that sendVoice() will become a private function and not global. To make it global, you'll need to explicitly assign it to the window object: window.sendVoice = function(){
Thank you, it's worked after making my method as global and +1 for your help :-)
1

For your example I think the best option is to use a callback:

So in your java you should use

PluginResult.Status status = PluginResult.Status.OK;
callbackContext.sendPluginResult(new PluginResult(status, ""));

And in your javascript you call the plugin like cordova.exec(sendVoice, null, "VoiceBotPlugin", "coolMethod", []); So when sendPluginResult is called it will execute sendVoice.

OLD: You are creating a new WebView, so it doesn't have access to your Cordova WebView, which is the one loading your javascript files.

If your class is a subclass of CordovaPlugin, you should be able to access the Cordova WebView with the webView variable.

So to call sendVoice() you should use webView.loadUrl("javascript:sendVoice();"); (note that you had javascript. and not javascript: in your example)

Also, sendVoice() should be a global function or it won't be able to find it.

If you are targetting Android 4.4 or newer you can use evaluateJavascript instead of `loadUrl``

Something like webView.getEngine().evaluateJavascript("sendVoice();", null);

Both of them should be run inside runOnUiThread as on DaveAlden answer.

7 Comments

Hi jcesarmobile, Thank you for your reply. I've tried with both the solution but i'm getting error like java.lang.NullPointerException: Attempt to invoke virtual method 'void android.webkit.WebView.evaluateJavascript(java.lang.String, android.webkit.ValueCallback)' on a null object reference and java.lang.NullPointerException: Attempt to invoke virtual method 'void android.webkit.WebView.loadUrl(java.lang.String)' on a null object reference
Can you share your whole .java class?
Please check my updated question. (I've used your suggested solution in execute method)
I've changed according to you but not getting expected result. Something wrong i'm doing. Can you please check these VoiceBotPlugin.js (line 20) and VoiceBotPlugin.java (line 61 and 62)
In your code it should be exec instead of cordova.exec as you are doing the var exec = require('cordova/exec');
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.