Как передать непримитивный объект из Java в JS с помощью Android addJavascriptInterface?



У меня были проблемы на эту тему (в течение нескольких дней).



Например, в основном, я хочу передать объект Java WebSocketClient в Android Webview JS по требованию , поэтому написал код, ссылающийся кому:




JAVA



    wv.addJavascriptInterface(new WebSocketFactory(), "factoryJ");

public class WebSocketFactory {
//.............
public WebSocket getInstance(String url) {
socket = new WebSocket(new URI(url));
return socket;
}
}


JS



 var url = "ws:someaddress";
var ws = factoryJ.getInstance(url);
console.log(ws.toString()) // object pointer displayed
console.log(ws.getReadyState()); //Uncaught Error: Error calling method on NPObject!


Uncaught Error: Error calling method on NPObject!



Эта концепция не работает, по крайней мере, для меня avove Android4.2+.,
потому что addJavascriptInterface() работает только с примитивными типами Java и Веревка.



Cf)




Насколько мне известно, единственный способ передать объект JAVA в JS - это:



wv.addJavascriptInterface(JavaObject, "JsObject");


Конечно, это должно работать нормально, пока передача JavaObject предопределена, но поскольку WebSocket Object(s) находится по требованию, мне нужно как-то взломать для этого.



Итак, я готовлюсь JavaObject как некий массив WebSocket .



   WebSocketNew[] ws = new WebSocketNew[99999];
wv.addJavascriptInterface(ws, "wsJ");


К сожалению, JS трактует wsJ[n] как undefined; похоже, что он также не может передать ArrayObject.



Я читал JSON или JSON array Java можно передать, но это string В конце концов и не может быть этим решением, я прав?



Вероятно, в былые времена взаимодействие Android Java-JS реализовывалось более свободно, но в вопросах безопасности они ограничивают больше (аннотация @JavascriptInterface является одной, и не только это, но и другие факторы ) Android 4.2.1, WebView и JavaScript интерфейсные разрывы



Как передать непримитивный объект из Java в JS с помощью Android addJavascriptInterface?



Есть мысли?



Спасибо.

639   2  

2 ответов:

Вы правы, что методы интерфейса Javascript могут возвращать только строки и примитивные типы. Если вам нужно вернуть более сложный объект, вы можете попробовать сериализовать объект в JSON. Но это работает только для объектов уровня модели. Если вам нужно вернуть класс, содержащий функциональность, единственный известный мне способ сделать это-обернуть класс и представить каждый из его методов как @JavascriptInterface. Например:

class Foo {
    private WrappedClass myWrappedClass;

    public Foo(WrappedClass classToWrap) {
        myWrappedClass = classToWrap;
    }

    @JavascriptInterface
    public String doSomething1() {
        return myWrappedClass.doSomething1();
    }

    @JavascriptInterface
    public int doSomething2() {
        return myWrappedClass.doSomething2();
    }

    // Etc.
}

Это довольно утомительно.

Но, похоже, что вы пытаетесь использовать websockets. А вы подумали Socket.io это позволит вам использовать веб-сокеты в Javascript, а не полагаться на JavascriptInterface.

Http://socket.io

Это был один из самых беспокойных хаков для меня.

Основная проблема возникает с Android UI-thread и non-UI-thread связывается с addJavascriptInterface

Во-первых, мое упоминание: насколько мне известно, единственный способ передать объект JAVA в JS-это : западная вирджиния.addJavascriptInterface (JavaObject, "JsObject"); неправильный.

Фактически, я мог бы передать WebSocketNew= мой пользовательский объект Java правильно в JS как возвращаемое значение getInstance.

Однако , объект, предназначенный для передачи / возврата JS должен находиться в области действия Android UI-thread.

Если мы просто делаем return new WebSocketNew(new URI(url))), он не найден JS, вероятно, потому, что JS работает в UI-потоке, а origin работает на non-UI-thread из addJavascriptInterface.

Как я уже упоминал ранее, так как экземпляр WebScoket находится по требованию, поэтому я решил сначала создать пул объектов в UI-thread. Это можно сделать с помощью HashMap с запрошенной строкой url.

Java

    final HashMap<String, WebSocketNew> ws = new HashMap<>();
    //runs on non-UI-thread
    class WebSocketFactory
    {
        public WebSocketFactory()
        {
        }

        @JavascriptInterface
        public WebSocketNew getInstance(String url)
        {
            System.out.println("============WebSocketFactory============getInstance  " + url);

            try
            {
                ws.put(url, new WebSocketNew(new URI(url)));
                ws.get(url).connect();

                System.out.println("=====WebSocketNew=====" + url + "  " + ws.get(url).getReadyState());

                return ws.get(url);
            }
            catch (Exception e)
            {
                System.out.println("==========ERROR");
                return null;
            }
        }
    }

    wv.addJavascriptInterface(new WebSocketFactory(), "factoryJ");

    wv.loadUrl("file:///android_asset/Content/app.html");

JS

         window.WebSocket = function(url)
         {
               console.log('####################creating new WebScoketInstance JS ' + url);

               var p = {
                     url: null
               };
               p.url = url;

               var ws = factoryJ.getInstance(p.url);

               var obj = {
                     send: function(data)
                     {
                           console.log('---  send: function(data)-----  ws.send1(data);------');
                           ws.send1(data);
                     },
              //.......
              //.......

               }
               return obj;


         };

Код JS связан с темой: реализация событий JavaScript для Объект на основе замыкания

Comments

    Ничего не найдено.