【问题标题】:Call javascript function from cordova java file从cordova java文件调用javascript函数
【发布时间】:2018-01-08 10:56:36
【问题描述】:

这个问题似乎是重复的,但我已经尝试过 SO 中的所有解决方案,但对我没有任何效果。

我的问题是,我想从cordova java 文件中调用javascript 函数(从CordovaPlugin 扩展而来)。为此,我检查了reference 1reference 2reference 3 以及网上的更多信息,但对我没有任何帮助

我的代码

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();");

我尝试在 java 文件中使用简单的警报,如下所示

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

我可以看到上面的alert,但是我无法从 java 文件中访问 javascript 函数。任何人都对此有想法

更新

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

}

【问题讨论】:

    标签: javascript java android cordova


    【解决方案1】:

    您可以尝试这样的事情 - cordovawebViewCordovaPlugin 类隐式定义:

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

    【讨论】:

    • 您好 DaveAlden,感谢您的回复。我已经尝试过您的解决方案。它对executeGlobalJavascript("alert('hello')"); 非常有效,但是当我尝试executeGlobalJavascript("sendVoice()"); 时它不起作用。在使用sendVoice() 时得到Uncaught ReferenceError: sendVoice is not defined at &lt;anonymous&gt;:1:1
    • Sample.js 正在加载,因此 sendVoice() 是否实际定义?尝试将 Chrome 开发工具连接到 webview 并从控制台手动执行sendVoice()
    • 是的 Sample.js 已加载,而 sendVoice() 仅在其中。我在 Chrome Dev 中检查了sendVoice(),得到了类似Uncaught ReferenceError: sendVoice is not defined 的错误。其他详情请查看VoiceBotPlugin.java(第 60 行和第 190 至 197 行)和VoiceBotPlugin.js
    • 问题是您在插件的 JS 组件中定义了sendVoice()。 Cordova 将包装它,这样sendVoice() 将成为私有函数而不是全局函数。要使其全局化,您需要将其显式分配给窗口对象:window.sendVoice = function(){
    • 谢谢,在将我的方法设置为全局方法并为您的帮助 +1 后,它已经奏效了 :-)
    【解决方案2】:

    对于您的示例,我认为最好的选择是使用回调:

    所以在你的java中你应该使用

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

    然后在您的 javascript 中调用插件,例如 cordova.exec(sendVoice, null, "VoiceBotPlugin", "coolMethod", []); 所以当sendPluginResult被调用时,它会执行sendVoice。

    旧: 您正在创建一个新的WebView,因此它无法访问您的 Cordova WebView,这是加载您的 javascript 文件的那个。

    如果您的类是CordovaPlugin 的子类,您应该能够使用webView 变量访问Cordova WebView

    所以要调用sendVoice(),你应该使用webView.loadUrl("javascript:sendVoice();");(注意你的例子中是javascript.而不是javascript:

    另外,sendVoice() 应该是一个全局函数,否则将无法找到它。

    如果您的目标是 Android 4.4 或更高版本,您可以使用 evaluateJavascript 而不是 `loadUrl``

    类似webView.getEngine().evaluateJavascript("sendVoice();", null);

    它们都应该在 runOnUiThread 中运行,就像 DaveAlden 的回答一样。

    【讨论】:

    • 您好 jcesarmobile,谢谢您的回复。我已经尝试了这两种解决方案,但我收到了java.lang.NullPointerException: Attempt to invoke virtual method 'void android.webkit.WebView.evaluateJavascript(java.lang.String, android.webkit.ValueCallback)' on a null object referencejava.lang.NullPointerException: Attempt to invoke virtual method 'void android.webkit.WebView.loadUrl(java.lang.String)' on a null object reference 之类的错误
    • 你能分享你的整个 .java 类吗?
    • 请检查我更新的问题。 (我在execute 方法中使用了您建议的解决方案)
    • 我已根据您的要求进行了更改,但没有得到预期的结果。我做错了什么。请检查一下VoiceBotPlugin.js(第 20 行)和VoiceBotPlugin.java(第 61 和 62 行)
    • 在您的代码中,它应该是 exec 而不是 cordova.exec,因为您正在执行 var exec = require('cordova/exec');
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 2013-06-20
    相关资源
    最近更新 更多