diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/plugins.qmltypes | 9 | ||||
-rw-r--r-- | src/jar/src/org/qtproject/qt5/android/view/QtAndroidWebViewController.java | 35 | ||||
-rw-r--r-- | src/webview/qquickwebview.cpp | 75 | ||||
-rw-r--r-- | src/webview/qquickwebview.h | 7 | ||||
-rw-r--r-- | src/webview/qwebview.cpp | 9 | ||||
-rw-r--r-- | src/webview/qwebview_android.cpp | 53 | ||||
-rw-r--r-- | src/webview/qwebview_android_p.h | 4 | ||||
-rw-r--r-- | src/webview/qwebview_ios.mm | 8 | ||||
-rw-r--r-- | src/webview/qwebview_ios_p.h | 4 | ||||
-rw-r--r-- | src/webview/qwebview_p.h | 3 | ||||
-rw-r--r-- | src/webview/qwebviewinterface_p.h | 3 |
11 files changed, 209 insertions, 1 deletions
diff --git a/src/imports/plugins.qmltypes b/src/imports/plugins.qmltypes index 8acf6fd..a0a57bf 100644 --- a/src/imports/plugins.qmltypes +++ b/src/imports/plugins.qmltypes @@ -20,5 +20,14 @@ Module { Method { name: "goForward" } Method { name: "reload" } Method { name: "stop" } + Method { + name: "runJavaScript" + Parameter { name: "script"; type: "string" } + Parameter { name: "callback"; type: "QJValue" } + } + Method { + name: "runJavaScript" + Parameter { name: "script"; type: "string" } + } } } diff --git a/src/jar/src/org/qtproject/qt5/android/view/QtAndroidWebViewController.java b/src/jar/src/org/qtproject/qt5/android/view/QtAndroidWebViewController.java index dd3cab0..404fa3a 100644 --- a/src/jar/src/org/qtproject/qt5/android/view/QtAndroidWebViewController.java +++ b/src/jar/src/org/qtproject/qt5/android/view/QtAndroidWebViewController.java @@ -63,12 +63,16 @@ public class QtAndroidWebViewController private Method m_webViewOnPause = null; private Method m_webSettingsSetDisplayZoomControls = null; + // API 19 methods + private Method m_webViewEvaluateJavascript = null; + // Native callbacks private native void c_onPageFinished(long id, String url); private native void c_onPageStarted(long id, String url, Bitmap icon); private native void c_onProgressChanged(long id, int newProgress); private native void c_onReceivedIcon(long id, Bitmap icon); private native void c_onReceivedTitle(long id, String title); + private native void c_onRunJavaScriptResult(long id, long callbackId, String result); private class QtAndroidWebViewClient extends WebViewClient { @@ -136,6 +140,11 @@ public class QtAndroidWebViewController m_webViewOnResume = m_webView.getClass().getMethod("onResume"); m_webViewOnPause = m_webView.getClass().getMethod("onPause"); m_webSettingsSetDisplayZoomControls = webSettings.getClass().getMethod("setDisplayZoomControls", boolean.class); + if (Build.VERSION.SDK_INT > 18) { + m_webViewEvaluateJavascript = m_webView.getClass().getMethod("evaluateJavascript", + String.class, + ValueCallback.class); + } } catch (Exception e) { /* Do nothing */ e.printStackTrace(); } } @@ -300,6 +309,32 @@ public class QtAndroidWebViewController return progress[0]; } + public void runJavaScript(final String script, final long callbackId) + { + if (script == null) + return; + + if (Build.VERSION.SDK_INT < 19 || m_webViewEvaluateJavascript == null) + return; + + m_activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + m_webViewEvaluateJavascript.invoke(m_webView, script, callbackId == -1 ? null : + new ValueCallback<String>() { + @Override + public void onReceiveValue(String result) { + c_onRunJavaScriptResult(m_id, callbackId, result); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + public String getUrl() { final String[] url = {""}; diff --git a/src/webview/qquickwebview.cpp b/src/webview/qquickwebview.cpp index be51fb7..1803994 100644 --- a/src/webview/qquickwebview.cpp +++ b/src/webview/qquickwebview.cpp @@ -38,6 +38,38 @@ #include <QtQml/qqmlengine.h> #include <QtCore/qmutex.h> +namespace { + +class CallbackStorage +{ +public: + int insertCallback(const QJSValue &callback) + { + QMutexLocker locker(&m_mtx); + const int nextId = qMax(++m_counter, 0); + if (nextId == 0) + m_counter = 1; + + m_callbacks.insert(nextId, callback); + return nextId; + } + + QJSValue takeCallback(int callbackId) + { + QMutexLocker lock(&m_mtx); + return m_callbacks.take(callbackId); + } + +private: + QMutex m_mtx; + int m_counter; + QHash<int, QJSValue> m_callbacks; +}; + +} // namespace + +Q_GLOBAL_STATIC(CallbackStorage, callbacks) + /*! \qmltype WebView \inqmlmodule QtWebView @@ -64,6 +96,7 @@ QQuickWebView::QQuickWebView(QQuickItem *parent) connect(m_webView.data(), &QWebView::loadingChanged, this, &QQuickWebView::loadingChanged); connect(m_webView.data(), &QWebView::loadProgressChanged, this, &QQuickWebView::loadProgressChanged); connect(m_webView.data(), &QWebView::requestFocus, this, &QQuickWebView::onFocusRequest); + connect(m_webView.data(), &QWebView::javaScriptResult, this, &QQuickWebView::onRunJavaScriptResult); } QQuickWebView::~QQuickWebView() @@ -185,6 +218,48 @@ void QQuickWebView::stop() m_webView->stop(); } +/*! + \qmlmethod void QtWebView::WebView::runJavaScript(string script, variant callback) + + Runs the specified JavaScript. + In case a callback function is provided, it will be invoked after the script finished running. + + \badcode + runJavaScript("document.title", function(result) { console.log(result); }); + \endcode +*/ +void QQuickWebView::runJavaScript(const QString &script, const QJSValue &callback) +{ + const int callbackId = callback.isCallable() ? callbacks->insertCallback(callback) + : -1; + runJavaScriptPrivate(script, callbackId); +} + +void QQuickWebView::runJavaScriptPrivate(const QString &script, int callbackId) +{ + m_webView->runJavaScriptPrivate(script, callbackId); +} + +void QQuickWebView::onRunJavaScriptResult(int id, const QVariant &variant) +{ + if (id == -1) + return; + + QJSValue callback = callbacks->takeCallback(id); + if (callback.isUndefined()) + return; + + QQmlEngine *engine = qmlEngine(this); + if (engine == 0) { + qWarning() << "No JavaScript engine, unable to handle JavaScript callback!"; + return; + } + + QJSValueList args; + args.append(engine->toScriptValue(variant)); + callback.call(args); +} + void QQuickWebView::onFocusRequest(bool focus) { setFocus(focus); diff --git a/src/webview/qquickwebview.h b/src/webview/qquickwebview.h index aab13b1..c36cc9d 100644 --- a/src/webview/qquickwebview.h +++ b/src/webview/qquickwebview.h @@ -84,6 +84,8 @@ public Q_SLOTS: void goForward() Q_DECL_OVERRIDE; void reload() Q_DECL_OVERRIDE; void stop() Q_DECL_OVERRIDE; + void runJavaScript(const QString& script, + const QJSValue &callback = QJSValue()); Q_SIGNALS: void titleChanged(); @@ -91,7 +93,12 @@ Q_SIGNALS: void loadingChanged(); void loadProgressChanged(); +protected: + void runJavaScriptPrivate(const QString& script, + int callbackId) Q_DECL_OVERRIDE; + private Q_SLOTS: + void onRunJavaScriptResult(int id, const QVariant &variant); void onFocusRequest(bool focus); private: diff --git a/src/webview/qwebview.cpp b/src/webview/qwebview.cpp index 9d55331..1865c7e 100644 --- a/src/webview/qwebview.cpp +++ b/src/webview/qwebview.cpp @@ -48,6 +48,8 @@ QWebView::QWebView(QObject *p) connect(d, SIGNAL(loadingChanged()), this, SIGNAL(loadingChanged())); connect(d, SIGNAL(loadProgressChanged()), this, SIGNAL(loadProgressChanged())); connect(d, SIGNAL(requestFocus(bool)), this, SIGNAL(requestFocus(bool))); + connect(d, &QWebViewPrivate::javaScriptResult, + this, &QWebView::javaScriptResult); } QWebView::~QWebView() @@ -150,6 +152,13 @@ void QWebView::setFocus(bool focus) d->setFocus(focus); } +void QWebView::runJavaScriptPrivate(const QString &script, + int callbackId) +{ + Q_D(QWebView); + d->runJavaScriptPrivate(script, callbackId); +} + void QWebView::init() { Q_D(QWebView); diff --git a/src/webview/qwebview_android.cpp b/src/webview/qwebview_android.cpp index be87a56..1ff4271 100644 --- a/src/webview/qwebview_android.cpp +++ b/src/webview/qwebview_android.cpp @@ -45,6 +45,7 @@ #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> #include <QtCore/qurl.h> +#include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE @@ -152,6 +153,24 @@ void QAndroidWebViewPrivate::setVisibility(QWindow::Visibility visibility) m_window->setVisibility(visibility); } +void QAndroidWebViewPrivate::runJavaScriptPrivate(const QString &script, + int callbackId) +{ + if (QtAndroidPrivate::androidSdkVersion() < 19) { + qWarning() << "runJavaScript() requires API level 19 or higher."; + if (callbackId == -1) + return; + + // Emit signal here to remove the callback. + Q_EMIT javaScriptResult(callbackId, QVariant()); + } + + m_viewController.callMethod<void>("runJavaScript", + "(Ljava/lang/String;J)V", + static_cast<jstring>(QJNIObjectPrivate::fromString(script).object()), + callbackId); +} + void QAndroidWebViewPrivate::setVisible(bool visible) { m_window->setVisible(visible); @@ -195,6 +214,37 @@ void QAndroidWebViewPrivate::onApplicationStateChanged(Qt::ApplicationState stat QT_END_NAMESPACE +static void c_onRunJavaScriptResult(JNIEnv *env, + jobject thiz, + jlong id, + jlong callbackId, + jstring result) +{ + Q_UNUSED(env) + Q_UNUSED(thiz) + + const WebViews &wv = (*g_webViews); + QAndroidWebViewPrivate *wc = static_cast<QAndroidWebViewPrivate *>(wv[id]); + if (!wc) + return; + + const QString &resultString = QJNIObjectPrivate(result).toString(); + + // The result string is in JSON format, lets parse it to see what we got. + QJsonValue jsonValue; + const QByteArray &jsonData = "{ \"data\": " + resultString.toUtf8() + " }"; + QJsonParseError error; + const QJsonDocument &jsonDoc = QJsonDocument::fromJson(jsonData, &error); + if (error.error == QJsonParseError::NoError && jsonDoc.isObject()) { + const QJsonObject &object = jsonDoc.object(); + jsonValue = object.value(QStringLiteral("data")); + } + + Q_EMIT wc->javaScriptResult(int(callbackId), + jsonValue.isNull() ? resultString + : jsonValue.toVariant()); +} + static void c_onPageFinished(JNIEnv *env, jobject thiz, jlong id, @@ -315,7 +365,8 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {"c_onPageStarted", "(JLjava/lang/String;Landroid/graphics/Bitmap;)V", reinterpret_cast<void *>(c_onPageStarted)}, {"c_onProgressChanged", "(JI)V", reinterpret_cast<void *>(c_onProgressChanged)}, {"c_onReceivedIcon", "(JLandroid/graphics/Bitmap;)V", reinterpret_cast<void *>(c_onReceivedIcon)}, - {"c_onReceivedTitle", "(JLjava/lang/String;)V", reinterpret_cast<void *>(c_onReceivedTitle)} + {"c_onReceivedTitle", "(JLjava/lang/String;)V", reinterpret_cast<void *>(c_onReceivedTitle)}, + {"c_onRunJavaScriptResult", "(JJLjava/lang/String;)V", reinterpret_cast<void *>(c_onRunJavaScriptResult)} }; const int nMethods = sizeof(methods) / sizeof(methods[0]); diff --git a/src/webview/qwebview_android_p.h b/src/webview/qwebview_android_p.h index 751b44f..45a0213 100644 --- a/src/webview/qwebview_android_p.h +++ b/src/webview/qwebview_android_p.h @@ -83,6 +83,10 @@ public Q_SLOTS: void reload() Q_DECL_OVERRIDE; void stop() Q_DECL_OVERRIDE; +protected: + void runJavaScriptPrivate(const QString& script, + int callbackId) Q_DECL_OVERRIDE; + private Q_SLOTS: void onApplicationStateChanged(Qt::ApplicationState state); diff --git a/src/webview/qwebview_ios.mm b/src/webview/qwebview_ios.mm index faa82c3..b9fdff9 100644 --- a/src/webview/qwebview_ios.mm +++ b/src/webview/qwebview_ios.mm @@ -283,4 +283,12 @@ void QIosWebViewPrivate::reload() [uiWebView reload]; } +void QIosWebViewPrivate::runJavaScriptPrivate(const QString &script, int callbackId) +{ + // ### TODO needs more async + NSString *result = [uiWebView stringByEvaluatingJavaScriptFromString:script.toNSString()]; + if (callbackId != -1) + Q_EMIT javaScriptResult(callbackId, QString::fromNSString(result)); +} + QT_END_NAMESPACE diff --git a/src/webview/qwebview_ios_p.h b/src/webview/qwebview_ios_p.h index 774d707..8302a68 100644 --- a/src/webview/qwebview_ios_p.h +++ b/src/webview/qwebview_ios_p.h @@ -86,6 +86,10 @@ public Q_SLOTS: void reload() Q_DECL_OVERRIDE; void stop() Q_DECL_OVERRIDE; +protected: + void runJavaScriptPrivate(const QString& script, + int callbackId) Q_DECL_OVERRIDE; + public: UIWebView *uiWebView; UIGestureRecognizer *m_recognizer; diff --git a/src/webview/qwebview_p.h b/src/webview/qwebview_p.h index 2a92620..578403a 100644 --- a/src/webview/qwebview_p.h +++ b/src/webview/qwebview_p.h @@ -93,10 +93,13 @@ Q_SIGNALS: void urlChanged(); void loadingChanged(); void loadProgressChanged(); + void javaScriptResult(int id, const QVariant &result); void requestFocus(bool focus); protected: void init(); + void runJavaScriptPrivate(const QString &script, + int callbackId) Q_DECL_OVERRIDE; private: friend class QQuickViewController; diff --git a/src/webview/qwebviewinterface_p.h b/src/webview/qwebviewinterface_p.h index 86d370c..ef02042 100644 --- a/src/webview/qwebviewinterface_p.h +++ b/src/webview/qwebviewinterface_p.h @@ -76,6 +76,9 @@ public: virtual void goForward() = 0; virtual void stop() = 0; virtual void reload() = 0; + + virtual void runJavaScriptPrivate(const QString &script, + int callbackId) = 0; }; #endif // QWEBVIEWINTERFACE_H |