From ee3c000b43522de4bfe78999039f7d1629f6f945 Mon Sep 17 00:00:00 2001 From: dimon4eg Date: Thu, 15 Oct 2015 16:43:53 +0300 Subject: [PATCH 1/5] Fix crash in web view on android --- cocos/ui/UIWebViewImpl-android.cpp | 83 ++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/cocos/ui/UIWebViewImpl-android.cpp b/cocos/ui/UIWebViewImpl-android.cpp index be30f0e544..7ca9d76e03 100644 --- a/cocos/ui/UIWebViewImpl-android.cpp +++ b/cocos/ui/UIWebViewImpl-android.cpp @@ -35,8 +35,11 @@ #include "UIWebView.h" #include "platform/CCGLView.h" #include "base/CCDirector.h" +#include "base/CCScheduler.h" #include "platform/CCFileUtils.h" #include "ui/UIHelper.h" +#include +#include #define CLASS_NAME "org/cocos2dx/lib/Cocos2dxWebViewHelper" @@ -45,7 +48,7 @@ static const std::string s_defaultBaseUrl = "file:///android_asset/"; static const std::string s_sdRootBaseUrl = "file://"; - static std::string getFixedBaseUrl(const std::string& baseUrl) +static std::string getFixedBaseUrl(const std::string& baseUrl) { std::string fixedBaseUrl; if (baseUrl.empty()) @@ -401,45 +404,73 @@ namespace cocos2d { setScalesPageToFitJNI(_viewTag, scalesPageToFit); } + // executed from Java's thread (we should invoke callback on cocos thread) bool WebViewImpl::shouldStartLoading(const int viewTag, const std::string &url) { - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; - if (webView->_onShouldStartLoading) { - return webView->_onShouldStartLoading(webView, url); + + std::mutex m; + std::condition_variable cv; + bool finished = false; + bool allowLoad = true; + + Director::getInstance()->getScheduler()->performFunctionInCocosThread([&]{ + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = s_WebViewImpls[viewTag]->_webView; + if (webView->_onShouldStartLoading) { + allowLoad = webView->_onShouldStartLoading(webView, url); + } } - } - return true; + + m.lock(); + finished = true; + m.unlock(); + cv.notify_one(); + }); + + // wait for result from cocos thread + std::unique_lock lk(m); + cv.wait(lk, [&finished]{ return finished; }); + + return allowLoad; } + // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::didFinishLoading(const int viewTag, const std::string &url){ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; - if (webView->_onDidFinishLoading) { - webView->_onDidFinishLoading(webView, url); + Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = s_WebViewImpls[viewTag]->_webView; + if (webView->_onDidFinishLoading) { + webView->_onDidFinishLoading(webView, url); + } } - } + }); } + // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::didFailLoading(const int viewTag, const std::string &url){ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; - if (webView->_onDidFailLoading) { - webView->_onDidFailLoading(webView, url); + Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = s_WebViewImpls[viewTag]->_webView; + if (webView->_onDidFailLoading) { + webView->_onDidFailLoading(webView, url); + } } - } + }); } + // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::onJsCallback(const int viewTag, const std::string &message){ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; - if (webView->_onJSCallback) { - webView->_onJSCallback(webView, message); + Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, message]{ + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = s_WebViewImpls[viewTag]->_webView; + if (webView->_onJSCallback) { + webView->_onJSCallback(webView, message); + } } - } + }); } void WebViewImpl::draw(cocos2d::Renderer *renderer, cocos2d::Mat4 const &transform, uint32_t flags) { From d317cd75e16738e796af6ad7b68613d4ae4784fd Mon Sep 17 00:00:00 2001 From: dimon4eg Date: Fri, 16 Oct 2015 11:28:34 +0300 Subject: [PATCH 2/5] Improved code a bit --- cocos/ui/UIWebViewImpl-android.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cocos/ui/UIWebViewImpl-android.cpp b/cocos/ui/UIWebViewImpl-android.cpp index 7ca9d76e03..2945cf324e 100644 --- a/cocos/ui/UIWebViewImpl-android.cpp +++ b/cocos/ui/UIWebViewImpl-android.cpp @@ -415,7 +415,7 @@ namespace cocos2d { Director::getInstance()->getScheduler()->performFunctionInCocosThread([&]{ auto it = s_WebViewImpls.find(viewTag); if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; + auto webView = it->second->_webView; if (webView->_onShouldStartLoading) { allowLoad = webView->_onShouldStartLoading(webView, url); } @@ -439,7 +439,7 @@ namespace cocos2d { Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ auto it = s_WebViewImpls.find(viewTag); if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; + auto webView = it->second->_webView; if (webView->_onDidFinishLoading) { webView->_onDidFinishLoading(webView, url); } @@ -452,7 +452,7 @@ namespace cocos2d { Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ auto it = s_WebViewImpls.find(viewTag); if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; + auto webView = it->second->_webView; if (webView->_onDidFailLoading) { webView->_onDidFailLoading(webView, url); } @@ -465,7 +465,7 @@ namespace cocos2d { Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, message]{ auto it = s_WebViewImpls.find(viewTag); if (it != s_WebViewImpls.end()) { - auto webView = s_WebViewImpls[viewTag]->_webView; + auto webView = it->second->_webView; if (webView->_onJSCallback) { webView->_onJSCallback(webView, message); } From 82bcbb03250af3fb36ff374be385cf3e8eec0338 Mon Sep 17 00:00:00 2001 From: dimon4eg Date: Wed, 21 Oct 2015 16:54:41 +0300 Subject: [PATCH 3/5] Revert: Fix crash in web view on android --- cocos/ui/UIWebViewImpl-android.cpp | 78 +++++++++--------------------- 1 file changed, 24 insertions(+), 54 deletions(-) diff --git a/cocos/ui/UIWebViewImpl-android.cpp b/cocos/ui/UIWebViewImpl-android.cpp index 2945cf324e..d22a6a1c7e 100644 --- a/cocos/ui/UIWebViewImpl-android.cpp +++ b/cocos/ui/UIWebViewImpl-android.cpp @@ -35,11 +35,8 @@ #include "UIWebView.h" #include "platform/CCGLView.h" #include "base/CCDirector.h" -#include "base/CCScheduler.h" #include "platform/CCFileUtils.h" #include "ui/UIHelper.h" -#include -#include #define CLASS_NAME "org/cocos2dx/lib/Cocos2dxWebViewHelper" @@ -404,73 +401,46 @@ namespace cocos2d { setScalesPageToFitJNI(_viewTag, scalesPageToFit); } - // executed from Java's thread (we should invoke callback on cocos thread) bool WebViewImpl::shouldStartLoading(const int viewTag, const std::string &url) { - - std::mutex m; - std::condition_variable cv; - bool finished = false; bool allowLoad = true; - - Director::getInstance()->getScheduler()->performFunctionInCocosThread([&]{ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = it->second->_webView; - if (webView->_onShouldStartLoading) { - allowLoad = webView->_onShouldStartLoading(webView, url); - } + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = it->second->_webView; + if (webView->_onShouldStartLoading) { + allowLoad = webView->_onShouldStartLoading(webView, url); } - - m.lock(); - finished = true; - m.unlock(); - cv.notify_one(); - }); - - // wait for result from cocos thread - std::unique_lock lk(m); - cv.wait(lk, [&finished]{ return finished; }); - + } return allowLoad; } - // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::didFinishLoading(const int viewTag, const std::string &url){ - Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = it->second->_webView; - if (webView->_onDidFinishLoading) { - webView->_onDidFinishLoading(webView, url); - } + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = it->second->_webView; + if (webView->_onDidFinishLoading) { + webView->_onDidFinishLoading(webView, url); } - }); + } } - // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::didFailLoading(const int viewTag, const std::string &url){ - Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, url]{ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = it->second->_webView; - if (webView->_onDidFailLoading) { - webView->_onDidFailLoading(webView, url); - } + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = it->second->_webView; + if (webView->_onDidFailLoading) { + webView->_onDidFailLoading(webView, url); } - }); + } } - // executed from Java's thread (we should invoke callback on cocos thread) void WebViewImpl::onJsCallback(const int viewTag, const std::string &message){ - Director::getInstance()->getScheduler()->performFunctionInCocosThread([viewTag, message]{ - auto it = s_WebViewImpls.find(viewTag); - if (it != s_WebViewImpls.end()) { - auto webView = it->second->_webView; - if (webView->_onJSCallback) { - webView->_onJSCallback(webView, message); - } + auto it = s_WebViewImpls.find(viewTag); + if (it != s_WebViewImpls.end()) { + auto webView = it->second->_webView; + if (webView->_onJSCallback) { + webView->_onJSCallback(webView, message); } - }); + } } void WebViewImpl::draw(cocos2d::Renderer *renderer, cocos2d::Mat4 const &transform, uint32_t flags) { From 7e43e28ca28db409726c20cc696d8e1dce13a182 Mon Sep 17 00:00:00 2001 From: dimon4eg Date: Wed, 21 Oct 2015 16:55:25 +0300 Subject: [PATCH 4/5] Fix crash in java code only --- .../src/org/cocos2dx/lib/Cocos2dxWebView.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java b/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java index cb28966f0d..3a2229746a 100755 --- a/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java +++ b/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java @@ -11,6 +11,27 @@ import android.widget.FrameLayout; import java.lang.reflect.Method; import java.net.URI; +import java.util.concurrent.CountDownLatch; + +class ShouldStartLoadingWorker implements Runnable { + private CountDownLatch mLatch; + private boolean[] mResult; + private final int mViewTag; + private final String mUrlString; + + ShouldStartLoadingWorker(CountDownLatch latch, boolean[] result, int viewTag, String urlString) { + this.mLatch = latch; + this.mResult = result; + this.mViewTag = viewTag; + this.mUrlString = urlString; + } + + @Override + public void run() { + this.mResult[0] = Cocos2dxWebViewHelper._shouldStartLoading(mViewTag, mUrlString); + this.mLatch.countDown(); // notify that result is ready + } +} public class Cocos2dxWebView extends WebView { private static final String TAG = Cocos2dxWebViewHelper.class.getSimpleName(); @@ -75,7 +96,20 @@ public class Cocos2dxWebView extends WebView { Log.d(TAG, "Failed to create URI from url"); } - return Cocos2dxWebViewHelper._shouldStartLoading(mViewTag, urlString); + boolean[] result = new boolean[] { true }; + CountDownLatch latch = new CountDownLatch(1); + + // run worker on cocos thread + activity.runOnGLThread(new ShouldStartLoadingWorker(latch, result, mViewTag, urlString)); + + // wait for result from cocos thread + try { + latch.await(); + } catch (InterruptedException ex) { + Log.d(TAG, "'shouldOverrideUrlLoading' failed"); + } + + return result[0]; } @Override @@ -102,7 +136,7 @@ public class Cocos2dxWebView extends WebView { }); } } - + public void setWebViewRect(int left, int top, int maxWidth, int maxHeight) { FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); From 27d5ad920e916507b78b8de7f12e1a85749023c2 Mon Sep 17 00:00:00 2001 From: dimon4eg Date: Wed, 21 Oct 2015 16:55:45 +0300 Subject: [PATCH 5/5] Update comment --- cocos/ui/UIWebView.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cocos/ui/UIWebView.h b/cocos/ui/UIWebView.h index 6b4e6a11d0..fb6468a0d1 100644 --- a/cocos/ui/UIWebView.h +++ b/cocos/ui/UIWebView.h @@ -147,10 +147,9 @@ public: /** * Call before a web view begins loading. - * Note: Any OpenGL related operations are forbidden in this callback. * * @param callback The web view that is about to load new content. - * @return YES if the web view should begin loading content; otherwise, NO . + * @return YES if the web view should begin loading content; otherwise, NO. */ void setOnShouldStartLoading(const std::function& callback);