Interaction between android and javascript under Cordova

Recently, a function was made. The company wrote the upper layer in html, and needed to call the voice synthesis and recognition that comes with android. I thought it was directly interacting with html, but I didn't expect the upper layer to be written in the framework of cordova. The interaction of android has been realized, now record the implementation process
Since it is the first time to use Cordova, I wrote its android project and implementation process together.

1. Build an android project with Cordova.

  • Download nodejs and configure environment variables (default)
    Open https://nodejs.org/en/ ,Download nodejs and install it. After installation, the environment variables are configured by default (the version I downloaded v4.5.0LTS). Enter npm and install it as shown in the figure.

  • Install Cordova npm install -g cordova

  • Create a cordova project cordova create (project name) (package name)

  • Configure this project to Android in this project directory (cd ProjectName) cordova platform add android

  • AndroidStudio imports this project

    ps: My androidStudio version is 2.1.2, the first import is very slow, I imported it for 20 minutes, and it has been stuck in the gradle loading interface after importing. In fact, it is not necessary, first import the project, then open the task manager and close the studio, and then re-import the project, almost instantly.

2. js calls android method

  • Create a java class that inherits CordovaPlugin. In this example, js calls the speak method in native
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");//If the success callback is not called, the successCallback in js will not be executed
            return true;
        }
        return false;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • Configure the plugin, under res/xml/config.xml, the value is the package name + class name

  • js call
    html is relatively simple, just a button, and the code will not be posted.

<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
  • Finally, call speak and print out the log

Three, android calls js method

js:

<script>
    <!-- android transfer js method -->
    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() {
                            //Cannot execute method of webview in child thread
                            loadUrl("javascript:showAlert(\"Hello\")");
                        }
                    });
                } 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

Since it needs to wait for the html to fully load the JS, the Android call will have no effect, otherwise there will be no response, so I let it wait in the child thread for 10 seconds and then call the js method in the main thread.

Fourth, CordOva loads the external network

After everything is done, import it into AndroidStudio. The web file is placed in assets and can run normally, but it cannot be loaded when placed in the external network.
I studied the hairstyle because in the CordovaLibs project, there is such a paragraph in the CordovaBridge file.

  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

Here it restricts the loading of the external network, so all loading is allowed. The code is as follows:

 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

Since the loading url of cordova is encapsulated in ConfigXmlParser under CordovaLib, in order to prevent other problems in modifying the url, I use EventBus to pass the 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);
        }

Tags: Vue

Posted by haku on Sat, 21 May 2022 15:21:55 +0300