Bahu
Bahu

Reputation: 1596

Call javascript function from cordova java file

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);*/
  }

}

Upvotes: 1

Views: 3372

Answers (2)

jcesarmobile
jcesarmobile

Reputation: 53351

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.

Upvotes: 1

DaveAlden
DaveAlden

Reputation: 30366

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);
            }
        });
    }
}

Upvotes: 6

Related Questions