升级到cordova 5 + cordova android 4.0.0后,menubutton不再工作了

时间:2015-05-18 17:23:48

标签: android cordova

我最近升级到了cordova 5,并在4.0.0版本中移除/重新创建了Android平台,并卸载/重新安装了所有插件。

我还必须将android sdk升级到sdk 22而不是21。

自更新以来,我不再能够按照the cordova documentation中的说明捕捉menubutton事件。

由于它在边缘文档中仍然被引用,我认为它应该仍在工作,我在发行说明中没有看到这一点。

后退按钮仍然有效。

我尝试将target-sdk设置为19,但它没有解决任何问题。

修改 我已经挖掘了cordova源代码并在CordovaWebViewImpl.java中找到了我发现了一个可疑的TODO评论:

   public void setButtonPlumbedToJs(int keyCode, boolean override) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_DOWN:
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_BACK:
                // TODO: Why are search and menu buttons handled separately?
                if (override) {
                    boundKeyCodes.add(keyCode);
                } else {
                    boundKeyCodes.remove(keyCode);
                }
                return;
            default:
                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
        }
    }

好吧,我的回答是"它应该......' T !!!!"

Cordova列出了要处理的键码,但没有添加菜单按钮,稍后只有在跳过键码后才将键码与KeyEvent.KEYCODE_MENU进行比较,因为它不在列表中。

我试图为菜单按钮添加一个案例,但事实证明只使用后退按钮的代码调用该函数。

所以现在我知道为什么它不起作用但仍然没有如何解决它。

编辑02/2016: 根据{{​​3}},menubutton的支持现在已在Cordova Android 5.1.0的java部分中修复,但仍未从javascript初始化。 目前,如Jira用户Keith Wong所示,您需要在添加事件监听器之前添加javascript调用:

document.addEventListener("deviceready", function() {
    ...
    navigator.app.overrideButton("menubutton", true);  // <-- Add this line
    document.addEventListener("menubutton", yourCallbackFunction, false);
    ...
}, false);

3 个答案:

答案 0 :(得分:4)

clarent的答案没有为我做,菜单按钮仍然没有响应。

我尝试了几个补丁,另一个建议是禁用boundKeyCodes检查完全没有这样做,因为那时后退行为会受到损害。

恢复旧行为的干净方法应如下所示。 boundKeyCodes检查确保仅在实际存在绑定到事件的自定义事件处理程序时才执行自定义行为。但是,在应用程序的JS代码中将事件处理程序绑定到“menubutton”不再触发将menubutton键代码添加到boundKeyCodes列表中。 这是因为setButtonPlumbedToJs方法永远不会首先对“menubutton”处理程序执行,即使这样,此方法中的switch语句也不会处理KEYCODE_MENU。

你可以很容易地恢复这种行为,首先你必须应用clarent建议的改变:

  1. 处理KEYCODE_MENU
  2. 在CordovaLib / src / org / apache / cordova / CoreAndroid.java(第357行,setButtonPlumbedToJs)中的

    在KEYCODE_BACK条目之后添加一个case语句,如下所示:

    public void setButtonPlumbedToJs(int keyCode, boolean override) {
      switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_DOWN:
        case KeyEvent.KEYCODE_VOLUME_UP:
        case KeyEvent.KEYCODE_BACK:
        case KeyEvent.KEYCODE_MENU:
        // TODO: Why are search and menu buttons handled separately?
          if (override) {
            boundKeyCodes.add(keyCode);
          } else {
            boundKeyCodes.remove(keyCode);
          }
          return;
        default:
          throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
      }
    }
    

    然后确保实际执行setButtonPlumbedToJs。你需要再做两次更改。

    1. 添加框架处理程序
    2. 在CordovaLib / src / org / apache / cordova / CoreAndroid.java(第243行,overrideButton)中,使方法如下所示(添加最后一个else-if子句):

      public void overrideButton(String button, boolean override) {
      
        if (button.equals("volumeup")) {
          webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
        }
        else if (button.equals("volumedown")) {
          webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
        }
        else if (button.equals("menubutton")) {
          webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);
        }
      }
      
      1. 添加javascript处理程序调用
      2. 在platform_www / cordova.js(第1532行左右,引导程序)更改此行:

        cordova.addDocumentEventHandler('menubutton');
        

        到此:

        var menuButtonChannel = cordova.addDocumentEventHandler('menubutton');
        menuButtonChannel.onHasSubscribersChange = function() {
          exec(null, null, APP_PLUGIN_NAME, "overrideButton", ['menubutton', this.numHandlers == 1]);
        };
        

        只要将事件处理程序添加到“menubutton”,这将触发框架overrideButton方法。

        应该这样做。我还添加了这个解决方案作为评论 https://issues.apache.org/jira/browse/CB-8921 并可能很快就会提出拉动请求。

答案 1 :(得分:0)

只需在函数setButtonPlumbedToJs中添加一行: case KeyEvent.KEYCODE_MENU:

      } else if (boundKeyCodes.contains(keyCode)) {
                String eventName = null;
                switch (keyCode) {
                    case KeyEvent.KEYCODE_VOLUME_DOWN:
                        eventName = "volumedownbutton";
                        break;
                    case KeyEvent.KEYCODE_VOLUME_UP:
                        eventName = "volumeupbutton";
                        break;
                    case KeyEvent.KEYCODE_SEARCH:
                        eventName = "searchbutton";
                        break;
                    case KeyEvent.KEYCODE_MENU:
                        eventName = "menubutton";
                        break;
                    case KeyEvent.KEYCODE_BACK:
                        eventName = "backbutton";
                        break;
                }

因此onDispatchKeyEvent开关将起作用:

{{1}}

答案 2 :(得分:0)

现在有了cordova-android 5.1,代码已经改变,我的补丁不再工作了(遗憾的是,没有补丁,菜单按钮在这个版本中仍无效)。

由于我希望能够升级平台而不必每次都检查代码,我搜索了一种让菜单按钮再次运行的新方法。

在cordova android 5.1中,事实证明,除了菜单按钮键永远不会添加到 boundKeyCoded 数组之外,所有按钮都在java代码中。

事实证明,这个数组需要通过javascript调用来填充(对于后退按钮和音量按钮,但是对于搜索按钮或菜单按钮都没有)。

缺少的代码是这样的:

exec(null, null, APP_PLUGIN_NAME, 'overrideButton', ['menubutton' , true]);

(来自 CoreAndroid.java 的js调用java函数 overrideButton 告诉将菜单按钮键添加到 boundKeyCodes 数组。

我认为此调用应添加到 platform.js ,但由于 platform.js 用于构建 cordova.js 平台添加,我决定创建一个 after_platform_add钩子来修补 cordova.js 文件。

这个钩子的优点是没有java更改,即使你使用不同的webview像十字路口也应该有效。

所以,首先,在 config.xml 中,在android部分添加钩子:

<platform name="android">
    ....
    ....
    <hook type="after_platform_add" src="scripts/android/patch_menubutton.js" />
    ....
    ....
</platform>

然后,在scripts文件夹中添加钩子文件 patch_menubutton.js

#!/usr/bin/env node
module.exports = function(ctx) {
    var fs = ctx.requireCordovaModule('fs'),
        path = ctx.requireCordovaModule('path');
    var CordovaJSPath = path.join(ctx.opts.projectRoot, 'platforms/android/platform_www/cordova.js');
    var data = fs.readFileSync(CordovaJSPath, 'utf8');
    var result = data.replace(new RegExp("cordova\\.addDocumentEventHandler\\('menubutton'\\);", "g"), "cordova.addDocumentEventHandler('menubutton'); exec(null, null, APP_PLUGIN_NAME, 'overrideButton', ['menubutton' , true]);");
    fs.writeFileSync(CordovaJSPath, result, 'utf8');
}

(它查找菜单按钮的事件处理程序的初始化,并将调用追加到 overrideButton 函数,如FewKinG答案的最后部分所述)