在 quick-cocos2d-x 中嵌入浏览器

原文地址:http://zengrong.net/post/2123.htm

[size=4](公告+吐槽) 这篇文章的内容我已经改过4遍,但为了保证良好的排版,我起码在这里编辑了20遍以上。论坛糟糕的编辑器让人吐血。
我修改文章非常频繁,即使是几年前的文章,如果有更新,我也会修改(这是病,得治~)。
所以,我决定不再修改这篇文章,麻烦大家移步看原文吧![/size]

2014-06-25 23:44:55 绝笔
[hr]

在游戏中嵌入网页是很常见的需求,cocos2d-x 引擎官方并没有提供这个功能。

我在网上转了一圈,把找到的资料做了一些修改,将其集成到我们使用的 quick-cocos2d-x 引擎中。

主要代码来自:CCXWebview这里 还有一篇专门讲解Android嵌入浏览器的文章,可以参考。

集成的类叫做 CCWebView,位于 extensions 之中。

效果如下:

[attachment=72735]

[size=5]做什么?[/size]

在游戏中,我们需要显示系统公告,或者制作一些需要复杂图文混排的界面,这些东西如果用 cocos2d-x 来做,未免太过麻烦。嵌入一个网页就简单的多。

现在的修改能满足这样一些简单的使用:

[list][li]显示一个指定地址的网页,设定网页的大小和位置;[/li][li]更新一个已经显示的网页的内容;[/li][li]关闭已经显示的网页。[/li][/list]

然后,就没有了。因为目前的项目不需要和浏览器交互,所以希望用 CCWebView 来实现一个商城的话可能会比较难办,要做一些扩展。

在 Android 中,浏览器与 Game 并不在一个线程,因此也没有提供把让cocos2d-x 来控制增加浏览器的关闭按钮之类的功能。如果要实现这些,最好的方法是浏览器不做全屏,然后用cocos2d-x实现一些按钮放在浏览器之上,点击按钮调用 CCWebView 的关闭函数。

[size=5]怎么做?[/size]

这里只放出lua代码,C++请脑补。

创建内嵌浏览器并显示一个网站:

<pre class="brush:lua; toolbar: true; auto-links: false;">-- 创建一个CCWebView,同时设置ActivityName为主Activity的包(后面会详述)
self._webview = CCWebView:create("us/t1201/testplayer/Testplayer")
self._webview:retain()
– 显示一个网页,坐标20,20(左上角为0,0),宽度1000, 高度500
self._webview:showWebView("http://zengrong.net", 20, 20, 1000, 500)
– 显示包名print("getActivityName:", self._webview:getActivityName())</pre>

更新已有浏览器中显示的网址,移除并销毁浏览器:

<pre class="brush:lua; toolbar: true; auto-links: false;">self._webview:updateURL("http://zengrong.net/post/2112.htm")
self._webview:removeWebView();
self._webview:release()
self._webview = nil</pre>

[size=5]封装[/size]
为了方便使用,我封装了一个 webview.lua 放在 framework 里面,这样只需要记住 show 和 remove 方法就好了。
由于C++中没有处理重复的CCWebView的情况,我把 webview 做成单例的,保证任何时候都只有一个 CCWebView 在工作。
使用这个封装,我写了一个完整的测试项目,看这里:

local WebViewTest = class(&quot;WebViewTest&quot;, function()
&#160;&#160;&#160; return display.newNode()
end)

function WebViewTest:ctor()
&#160;&#160;&#160; self:_showUI()
&#160;&#160;&#160; self:_test()
end

function WebViewTest:_test()
&#160;&#160;&#160; webview.setActivityName(&quot;us/t1201/testplayer/Testplayer&quot;)
&#160;&#160;&#160; print(&quot;getActivityName:&quot;, webview.getActivityName())
end

function WebViewTest:_showUI()
&#160;&#160;&#160; local __menu = ui.newMenu({
&#160;&#160;&#160;&#160;&#160;&#160;&#160; ui.newTTFLabelMenuItem(
&#160;&#160;&#160;&#160;&#160;&#160;&#160; {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; text=&quot;show(http://zengrong.net, 20,20,1000,500)&quot;,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; listener = function()
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; webview.show(&quot;http://zengrong.net&quot;, 20,20, 1000, 500)
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; end
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }),
&#160;&#160;&#160;&#160;&#160;&#160;&#160; ui.newTTFLabelMenuItem(
&#160;&#160;&#160;&#160;&#160;&#160;&#160; {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; text=&quot;show(http://zhihu.com, 0,0,500,300)&quot;,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; listener = function()
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; webview.show(&quot;http://zhihu.com&quot;, 0,0, 500, 300)
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; end
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }),
&#160;&#160;&#160;&#160;&#160;&#160;&#160; ui.newTTFLabelMenuItem(
&#160;&#160;&#160;&#160;&#160;&#160;&#160; {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; text=&quot;show(http://github.com)&quot;,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; listener = function()
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; webview.show(&quot;http://github.com&quot;)
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; end
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }),
&#160;&#160;&#160;&#160;&#160;&#160;&#160; ui.newTTFLabelMenuItem(
&#160;&#160;&#160;&#160;&#160;&#160;&#160; {
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; text=&quot;remove()&quot;,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; listener = function()
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; webview.remove()
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; end
&#160;&#160;&#160;&#160;&#160;&#160;&#160; }),
&#160;&#160;&#160; })
&#160;&#160;&#160;&#160;&#160;&#160;&#160; :addTo(self)
&#160;&#160;&#160;&#160;&#160;&#160;&#160; :pos(display.cx,display.bottom+100)
&#160;&#160;&#160; __menu:alignItemsVertically()
end

return WebViewTest

需要注意的是,在上面的例子中,如果希望改变已有的内嵌浏览器的大小,必须先remove才可以生效。

[size=5]跨平台[/size]

目前内嵌浏览器仅支持 iOS 和Android 平台。以下是一些需要注意的地方:

[size=4]Android 平台[/size]

在创建CCWebView的时候必须提供你的项目的主Activity的包路径和类名。CCWebView 需要结合主Activity中提供的一些方法才能工作。这些方法我已经添加到项目模板中。
注意写包路径和类名的格式与JAVA的习惯不同,需要把点 . 替换成斜线 / 。

使用 getActivityName() 方法可以返回传入的包名。

[size=4]iOS 平台[/size]

iOS不需要提供包名,因此可以直接使用不带参数的 create() 方法来创建 CCWebView 。但为了避免判断平台使用不同的创建方法,也可以直接传入 Android 中需要的包名。iOS平台下的代码不会记录和处理这个值。
使用 getActivityName() 方法将总是返回空字符串。

在iOS平台上,浏览器的分辨率设定是个问题。对于高清设备,你传递的值其实是真实值的一半。例如在iPhone5上调用这句:

<pre class="brush:lua; toolbar: true; auto-links: false;">showWebView("http://zengrong.net", 20, 20, 1000, 500)</pre>

那么最终显示的效果是浏览器宽度超出屏幕。因为这里的宽度1000其实等于2000。
而在标清设备上(例如iPad2),传递的宽度就是真实的宽度。

[size=4]Mac OS X 平台[/size]

在 quick-x 的 Mac 模拟器中,调用 CCWebView 的方法将不会有任何作用。

[size=4]Windows 平台[/size]

目前可能无法编译 quick-x Windows 模拟器,我正在安装 Virtual Box 来解决这个问题。

好帖,顶。

吐槽一下,编辑器太难用了。

不能支持markdown么?

好文 先顶

这个很赞!非常实用的功能。一般都会考虑集成第三方代码,但选择时很难,现在Jacky帮大家选好了,放心用就是,呵呵。

谢谢 zrong = jacky 优秀文章

好文, 感谢分享.

白打那么多字了。。
收藏。。以后肯定会用到的。。顶好文。

~~ MARK ~~

这个好,顶一下。

好东西,mark一下

要崩溃了,编辑十几遍,为啥语法高亮会自动往代码中的链接里面加上url wind代码?怎么关闭自动识别链接?

这个太帅了,必须加入quick

论坛编辑器确实蛋疼,正在开发支持 markdown 的编辑器。

廖大发话了,还有什么不可以的。

话说~ 帮忙报销点电费?AMD 很耗电的说 :890:

调用各个平台的浏览器内核放到窗口里面而已

习惯了使用device.openURL,直接打开网页,比较新鲜。

mark~~~~~~~~~

学习了!
还想问个问题,如果希望在WebView上面添加cocos的按钮图标等元素可行吗?有什么解决思路?还望求诸位大大指导:14: