apache / cordova-android

Apache Cordova Android
https://cordova.apache.org/
Apache License 2.0
3.59k stars 1.52k forks source link

websockets don't work #1610

Closed treecaptcha closed 5 months ago

treecaptcha commented 1 year ago

Bug Report

Problem

Websockets never connect or fail to connect

What is expected to happen?

When a websocket is created it should connect or fail to connect and print an error in the console.

What does actually happen?

The websocket does neither

Information

Command or Code

console.log("(C) 2023");

function sendMSG(Event) {
  Event.preventDefault() 
  if (websock == null || websock.readyState != 1){
    console.log("patience is a virtue")
    return;
  }
  const txt = document.getElementsByClassName('messagebox')[0].value;
  websock.send("send;" + uuid + ";" + id + ";" + txt);
  document.getElementsByClassName('messagebox')[0].value = "";
}

document.getElementsByClassName('textsubmit')[0].addEventListener('submit',sendMSG);

// socks are cool!
var websock = new WebSocket('ws://[redacted]:8443'); 
var id;
var uuid;
function autoGet(){
if (websock == null || websock.readyState != 1){
    return;
  }
  websock.send("get;" + uuid + ";" + id);
}
websock.addEventListener('open', (event) => {
    console.log("Connection open with ", websock.url);
    websock.send("new");
    websock.send("get;" + uuid + ";" + id);
    setInterval(autoGet, 5000);
});

websock.addEventListener('message', (event) => {
    console.log("Message: ", event.data);
    const components = (event.data + "").split(";");
    if (components[0] == "new"){
        console.log("recived new login data");
        uuid = components[1];
        id = components[2];

    }
    if (components[0] == "send"){
        console.log("GOT A UPDATE");
        document.getElementsByClassName('text')[0].innerHTML = components[1]
    }
});
function awake(){
    console.log("I'm still awake");
}
setInterval(awake, 5000);

console.log(websock);
console.log("done with main.js");

No error is logged and "I'm still awake" is printed every 5 seconds

Environment, Platform, Device

Android Studio Emulator Pixel 3 API 33

Version information

Cordova 11.1.0 Cordova Android 10.1.2

Checklist

treecaptcha commented 1 year ago

I forgot to add that this code does work when run in google chrome

breautek commented 1 year ago

Testing via https://socketsbay.com/test-websockets shows websockets are working for me.

Note on CSP

Cordova's default configuration doesn't allow websocket connections, but you'll get an CSP (Content Security Policy) error for that.

At minimum, you'll need to add to your <meta http-equiv="Content-Security-Policy":

connect-src: ws: wss:;

Ideally you'd include the full domain + port to limit connects to a specific server, and you should be using wss (secure sockets) instead of ws, so ideally ws: would be completely omitted, but could be included for development builds.

Note on Secure Connections

I'm unable to test ws protocol specifically, however this would yield a connection error (at least it does for XHR...) But both the android platform and browsers generally forbid non-secure protocols by default, with some exceptions (e.g. I think localhost is allowed on browsers). The android platform (including completely native apps) by default forbids all insecure connection types. It would be recommended to use wss:// if possible. If this is a local test server, then you may be able to work around it by declaring that you use cleartext traffic. This should be used for your development environment only.

Inside the config.xml:

<platform name="android">
  <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
      <application android:usesCleartextTraffic="true" />
  </edit-config>
</platform>

If the config.xml doesn't declare the android namespace already, you'll also need to add xmlns:android="http://schemas.android.com/apk/res/android" to the root widget tag.

Other thoughts

Having no error is strange. Note that Cordova doesn't implement this feature. It's provided by the underlying android system webview. So if there is a bug where a websocket is not returning an error as expected, chances are that bug will need to be filed upstream to Chromium.

Please let me know how my above hints works for you. If there is still a problem, we'll need a sample app along with a sample test server.

ksch10bob commented 1 year ago

@treecaptcha Emulator Images are shipped with initial versions of android system webview

To be sure it is not a system webview issue you can try the following Create an emulated devices with an API 33 image that includes the playstore App Login in with an google Account an look for android system webview in the playstore App on emulated device und update the App android system webview

We had some issues with the correct handling of cookies with the initial version of android system webview on the API 33 emulator image.

treecaptcha commented 1 year ago

@ksch10bob I got let’s encrypt certs installed yesterday and I’ll check today if it is working. If not should I try the latest API 32?

breautek commented 1 year ago

Emulator Images are shipped with initial versions of android system webview

Websocket support has been implemented in the system webview since Android 4.4, which used Chrome 30 (fixed). Android AOSP 5.1 ships with Chrome 33 if I recall, and every AOSP emulator ships with some chrome version later than the previous Android version, so even using base AOSP images, the webview should have support for it.

I was also doing test using AOSP emulators and they appeared to work fine, at least with the testing server I used.

But it definitely doesn't hurt to use a Google Play image so that you can get access to the latest webview version to test with, if you don't have a physical device for that.

I got let’s encrypt certs installed yesterday and I’ll check today if it is working. If not should I try the latest API 32?

There really shouldn't be any changes regarding web socket support between cordova-android@10 and cordova-android@11 since Cordova Framework doesn't implement web sockets (or any browser features for that matter) and the underlying webview should be the same. However, API 32 is currently required for deploying to Google Play and support API 32 is available in cordova-android@11, so I would still recommending upgrading cordova-android to version 11.

Trying to target API 32 on cordova-android@10 likely will not work or be difficult as it had a lot of breaking changes in the native build tools.

treecaptcha commented 1 year ago

I can't even get the app to install now

Failed to measure fs-verity, errno 1: /data/app/~~WudBEzYVvZ5XnHqZNYjEMQ==/[a reverse domain]-11ieJDzmZHyF8VqqLQU_fg==/base.apk
treecaptcha commented 1 year ago

I found the issue. The websocket on Android does not work unless there is a terminating / in the url. So wss://hello.example.com:8443 will not work; however wss://hello.example.com:8443/ will.

jcesarmobile commented 5 months ago

closing since you figured out

this still seems like a WebView bug, so you should probably report it to google so you don't need the workaround of adding a / for Android only