Как вызвать JavaScript из Android? - PullRequest
       10

Как вызвать JavaScript из Android?

11 голосов
/ 25 сентября 2011

Как мы называем JavaScript с Android? У меня есть эта библиотека javascript, которую я хотел бы использовать, я хочу вызвать функцию javascript и передать значение результата в java-код Android. Не нашел ответа с этого момента. мне удалось вызвать код Android из JavaScript, но я хочу наоборот.

Ответы [ 4 ]

18 голосов
/ 25 сентября 2011

Есть взлом:

  1. Привязать некоторый объект Java, чтобы его можно было вызывать из Javascript с помощью WebView:

    addJavascriptInterface(javaObjectCallback, "JavaCallback")
    
  2. Принудительное выполнение JavaScript на существующей странице с помощью

    WebView.loadUrl("javascript: var result = window.YourJSLibrary.callSomeFunction();
        window.JavaCallback.returnResult(result)");
    

(в этом случае ваш Java-класс JavaObjectCallback должен иметь метод returnResult(..))

Примечание: это угроза безопасности - любой код JS на этой веб-странице может получить доступ / вызвать ваш связанный Java-объект. Лучше всего передать одноразовые куки в loadUrl () и передать их обратно вашему Java-объекту, чтобы убедиться, что ваш код выполняет вызов.

3 голосов
/ 07 апреля 2015

Вы можете использовать библиотеку Rhino для выполнения JavaScript без WebView.

Сначала загрузите Rhino , разархивируйте его, поместите файл js.jar в папку libs. Он очень маленький, поэтому вам не нужно беспокоиться о том, что ваш apk-файл будет смехотворно большим из-за этого одного внешнего фляги.

Вот простой код для выполнения кода JavaScript.

Object[] params = new Object[] { "javaScriptParam" };

// Every Rhino VM begins with the enter()
// This Context is not Android's Context
Context rhino = Context.enter();

// Turn off optimization to make Rhino Android compatible
rhino.setOptimizationLevel(-1);
try {
    Scriptable scope = rhino.initStandardObjects();

    // Note the forth argument is 1, which means the JavaScript source has
    // been compressed to only one line using something like YUI
    rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);

    // Get the functionName defined in JavaScriptCode
    Object obj = scope.get(functionNameInJavaScriptCode, scope);

    if (obj instanceof Function) {
        Function jsFunction = (Function) obj;

        // Call the function with params
        Object jsResult = jsFunction.call(rhino, scope, scope, params);
        // Parse the jsResult object to a String
        String result = Context.toString(jsResult);
    }
} finally {
    Context.exit();
}

Вы можете увидеть более подробную информацию на мой пост .

2 голосов
/ 11 декабря 2014

Чтобы соответствовать вызовам методов iOS WebviewJavascriptBridge (https://github.com/marcuswestin/WebViewJavascriptBridge), я создал прокси для вызовов register_handle и call_handle.Обратите внимание, что я не гуру Javascript, поэтому, вероятно, есть лучшее решение.

     javascriptBridge = (function() {
        var handlers = {};
        return {
            init: function () {
            },
            getHandlers : function() {
                return handlers;
            },
            callHandler : function(name, param) {
                if(param !== null && param !== undefined) {
                    JSInterface[name](param);
                } else {
                    JSInterface[name]();
                }
            },
            registerHandler : function(name, method) {
                if(handlers === undefined) {
                    handlers = {};
                }
                if(handlers[name] === undefined) {
                    handlers[name] = method;
                }
            }
        };
    }());

Таким образом, вы можете отправлять из Javascript вызовы Java, которые могут иметь параметр String

javascriptBridge.callHandler("login", JSON.stringify(jsonObj));

вызывает

@JavascriptInterface
public void login(String credentialsJSON)
{
    Log.d(getClass().getName(), "Login: " + credentialsJSON);
    new Thread(new Runnable() {
         public void run() {              
             Gson gson = new Gson();
             LoginObject credentials = gson.fromJson(credentialsJSON, LoginObject.class);
             SingletonBus.INSTANCE.getBus().post(new Events.Login.LoginEvent(credentials));
         }
    }).start();
}

, и вы можете перезвонить в Javascript с помощью

javascriptBridge.registerHandler('successfullAuthentication', function () {
    alert('hello');
})

и

private Handler webViewHandler = new Handler(Looper.myLooper());

webViewHandler.post(
        new Runnable()
        {
            public void run()
            {
                webView.loadUrl("javascript: javascriptBridge.getHandlers().successfullAuthentication();"
            }
        }
);

Если вам нужно передать параметр, сериализуйте вЗатем в строку JSON вызывается StringEscapeUtils.escapeEcmaScript(json), в противном случае вы получите ошибку unexpected identifier: source (1).

Немного безвкусно и хакерски, но это работает.Вам просто нужно удалить следующее.

connectWebViewJavascriptBridge(function(bridge) {
}

РЕДАКТИРОВАТЬ:

, чтобы изменить глобальную переменную на фактическое свойство, я изменил приведенный выше код на следующее:

(function(root) {
    root.bridge = (function() {
        var handlers = {};
        return {
            init: function () {
            },
            getHandlers : function() {
                return handlers;
            },
            callHandler : function(name, param) {
                if(param !== null && param !== undefined) {
                    Android[name](param);
                } else {
                    Android[name]();
                }
            },
            registerHandler : function(name, method) {
                if(handlers === undefined) {
                    handlers = {};
                }
                if(handlers[name] === undefined) {
                    handlers[name] = method;
                }
            }
        };
    }());
})(this);

Я получил идею от глобального модуля Javascript или глобальной переменной .

1 голос
/ 07 января 2016

Для полной реализации JavaScript, который не требует использования медленного WebView, см. AndroidJSCore , который является полным портом JavaScript WebCit для Android.

ОБНОВЛЕНИЕ2018: AndroidJSCore устарела.Тем не менее, его преемник, LiquidCore имеет все те же функции и многое другое.

Вызов функций из Android очень прост:

JSContext context = new JSContext();
String script =
  "function factorial(x) { var f = 1; for(; x > 1; x--) f *= x; return f; }\n" +
  "var fact_a = factorial(a);\n";
context.evaluateScript("var a = 10;");
context.evaluateScript(script);
JSValue fact_a = context.property("fact_a");
System.out.println(df.format(fact_a.toNumber())); // 3628800.0
...