Cordova下android与javascript的交互

来源:互联网 发布:尤克里里谱制作软件 编辑:程序博客网 时间:2024/05/18 11:34

http://blog.csdn.net/adzcsx2/article/details/52597088


目录(?)[+]

最近做了一个功能,公司是用html写的上层,需要调用android自带的语音合成和识别,原以为是直接与html交互,结果没想到上层是用cordova的框架写的,研究一天把cordova与android的交互实现了,现在记录一下实现流程 
由于是第一次用到Cordova,所以把它的搭建android项目和实现流程一并写上。


一、用Cordova搭建一个android工程。

  • 下载nodejs,并配置环境变量(默认) 
    打开https://nodejs.org/en/,下载nodejs并安装,安装好默认是配置好环境变量的(我下载的v4.5.0LTS这个版本),输入npm如图即装好 
    nodejs

  • 安装Cordova      npm install -g cordova

    Cordova

  • 创建一个cordova工程     cordova create (工程名) (包名)

    这里写图片描述

  • 将这个工程配置到Android      在这个工程目录下(cd ProjectName) cordova platform add android

    add2android

  • AndroidStudio 导入这个项目

    studio

    ps:我的androidStudio版本是2.1.2,第一次导入特别慢,我导入了20分钟,导入了之后一直卡在gradle加载界面。实际上并不需要,先导入项目,然后打开任务管理器关闭studio之后再重新导入项目,几乎瞬间就好了。

二、js调用android方法

  • 创建一个java类,继承CordovaPlugin。本例是js调用native中的speak方法
public class SpeechOFFSynthesize extends CordovaPlugin{    public void speak(String content){        Log.e("SpeechOFFSynthesize",content);    }    @Override    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {        if("speak".equals(action)){            //speechSynthesize            String content = args.getString(0);            speak(content);            callbackContext.success("finish");//如果不调用success回调,则js中successCallback不会执行            return true;        }        return false;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 配置插件,在res/xml/config.xml下,value为包名+类名

    plugin

  • js调用 
    html比较简单,就一个button,代码就不贴了。

<script>    $("#button").click(function(){         cordova.exec(success, fail, "SpeechOFFSynthesize", "speak", ["haha"]);    });    var success = function(message){            alert("success = "+message);         };    var fail = function(message){            alert("fail = "+message);         };</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 最后就是调用speak,打出日志了 
    result

三、android调用js方法

js:

<script>    <!-- android调用js方法 -->    function showAlert(content){        alert(content);    }</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

android:

public class MainActivity extends CordovaActivity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // Set by <content src="index.html" /> in config.xml        loadUrl(launchUrl);        new Thread(new Runnable() {            @Override            public void run() {                try {                    Thread.sleep(10000);                    runOnUiThread(new Runnable() {                        @Override                        public void run() {                            //不能在子线程中执行webview的方法                            loadUrl("javascript:showAlert(\"你好\")");                        }                    });                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }).start();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

由于需要等html完全加载完JS之后,Android的调用才能有效果,否则会没反应,所以我让它在子线程中等待了10秒然后在主线程中去调用js的方法。

四、CordOva加载外网

所有东西弄完了之后,导入到AndroidStudio里面,web文件是放在assets里面,能正常运行,可是放在外网里,却无法加载。 
研究了一下发型是因为在CordovaLibs工程里,CordovaBridge文件中,有这样一段。

  else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {            // Protect against random iframes being able to talk through the bridge.            // Trust only pages which the app would have been allowed to navigate to anyway.            if (pluginManager.shouldAllowBridgeAccess(origin)) {//                 Enable the bridge                int bridgeMode = Integer.parseInt(defaultValue.substring(9));                jsMessageQueue.setBridgeMode(bridgeMode);                // Tell JS the bridge secret.                int secret = generateBridgeSecret();                return ""+secret;            } else {                Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin);            }            return "";        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这里它限制了外网的加载,所以允许所有加载即可,代码如下:

 else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {            // Protect against random iframes being able to talk through the bridge.            // Trust only pages which the app would have been allowed to navigate to anyway.//            if (pluginManager.shouldAllowBridgeAccess(origin)) {                // Enable the bridge                int bridgeMode = Integer.parseInt(defaultValue.substring(9));                jsMessageQueue.setBridgeMode(bridgeMode);                // Tell JS the bridge secret.                int secret = generateBridgeSecret();                return ""+secret;//            } else {//                Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin);//            }//            return "";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

由于cordova的加载url是封装在CordovaLib下的ConfigXmlParser,为了防止修改url出现其他问题,所以我是用 EventBus,将url传过去的。

 private void setStartUrl(String src) {        Pattern schemeRegex = Pattern.compile("^[a-z-]+://");        Matcher matcher = schemeRegex.matcher(src);        if (matcher.find()) {            launchUrl = src;        } else {            if (src.charAt(0) == '/') {                src = src.substring(1);            }            launchUrl=  EventBus.getDefault().getStickyEvent(String.class);        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

原创粉丝点击