首页 > Personal > cocos2d-x > cocos2d-x: 游戏内显示网页
2013
12-24

cocos2d-x: 游戏内显示网页

前一篇文章OAuth2已经提到了,游戏内显示网页的原因,现在说下具体方法。Windows和Mac,一位不是cocos2d-x的开发重点,但是调试的时候也不能少,所以用了个简单的办法跳过这个问题,就是从游戏中弹出一个网页让系统处理,然后再拷贝浏览器获得的code值再拷回游戏里。

Windows
在请求网页的地方调用
ShellExecuteA(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL);
系统默认浏览器会打开相应网页。

Mac
在请求网页的地方调用
NSString* ns_str = [NSString stringWithUTF8String:url];
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:ns_str]]
和Windows一样,系统默认浏览器会打开相应网页。

这两个系统游戏方面的实现是一样的,就是在CCDirector::sharedDirector()->getRunningScene();当前运行的scene上添加一个CCEditBox填入得到的code,一个CCControlButton用来确认输入。

如果Windows和Mac想做的更好,也可以用第三方的库,在游戏中自己绘制实现网页。比如AwesomiumLLMozLibwxwidget。或者通过WebKit去实现,如LLQtWebKit。Windows的话还可以使用CAxWindow控件。重点不在这两个平台就没有多研究,有兴趣的话网上可以找到很多方法。

IOS
通过代理类,调到object-c的实现类,再生成相应网页,该类需要继承自
NSObject<UIWebViewDelegate>
mm文件中加入头文件
#import “EAGLView.h”
创建一个UIVIew
view = [[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)]; // 创建view
[[EAGLView sharedEGLView] addSubview:view]; // 加入到sharedEGLView
算出button和webview的高度
int button_height;
int web_view_height = height – button_height;
创建UIWebView
web_view = [[UIWebView alloc] initWithFrame:CGRectMake(x, y + button_height, width, web_view_height)];
[web_view setDelegate:self];
[web_view setScalesPageToFit:YES]; //用来保证页面在屏幕中自适应,不过虚拟机iphone好像不对
[web_view setBackgroundColor:[UIColor clearColor]];
[web_view setOpaque:YES]; // 优化,说明该空间不透明
[view addSubview:web_view]; // 加入到view中
[web_view release];
创建UIToolbar,用来放button和spinner
toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(x, y, width, button_height)];
[toolbar setTintColor:[UIColor blackColor]];
[view addSubview:toolbar];
[toolbar release]
创建UIBarButtonItem和UIActivityIndicatoerView(用来做加载中显示)
button_back = [[UIBarButtonItem alloc] initWithTitle:@”Back” style:UIBarButtonItemStyleDone target:self action:@selector(backCallback:)]; // 设置按键回调
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[toolbar setItems:[NSArray arrayWithObjects:button_back, [[[UIBarButtonItem alloc] initWithCustomView:spinner] autorelease], nil] animated:YES]; // 加入toolbar
[button_back release];
[spinner release]
重载UIWebViewDelegate,网页请求时调用
[web_view loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:request] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60]]
重载UIWebViewDelegate,网页开始加载时
– (void)webViewDidStartLoad:(UIWebView *)webView {
[spinner startAnimating];
}
重载UIWebViewDelegate,网页结束加载时
– (void)webViewDidFinishLoad:(UIWebView *)webView {
[spinner stopAnimating];
}
重载UIWebViewDelegate,网页出错时
– (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
调回游戏中
}
重载UIWebViewDelegate,网页加载前,也是只要处理部分
– (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
webView.scalesPageToFit = YES;
if (m_delegate) {
NSString* url = 网页需要终止的url,一般就是OAuth的回调页;
NSString* request_url = request.URL.absoluteString;
if ([request_url rangeOfString:url].location == 0) { // 判断如果是回调也的话
做相应处理,调回游戏中。
return NO; // 不在继续处理
}
}
return YES; // 继续处理
}
shouldStartLoadWithRequest的返回值如果是NO的话webView不会再处理该url了,如果是YES的则会继续处理。
基本就实现就是这些。

Android
因为android的系统调用要使用java,所以需要用到cocos2d-x: jni c++ java相互通信。在proj.android的src里.java文件中加入相应实现,需要用到的import
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.graphics.Color;
import android.R;
在类创建时,赋值instance_ ,并创建一个FrameLayout加入到ContentView中
instance_ = this;
rootLayout = new FrameLayout(instance_);
addContentView(rootLayout, new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
加入一个接口让c++可以获得类的实例
// webview get instance
public static fly getInstance() {
return instance_;
}
添加函数用来打开url
// webview open url
public void openUrl(final String url) {
this.runOnUiThread(new Runnable() { // 需要在ui线程创建
public void run() {
// web view
m_webView = new WebView(instance_); // 常见WebView
m_webView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT)); // 设置layout
m_webView.getSettings().setJavaScriptEnabled(true); // 允许javascript
m_webView.getSettings().setUseWideViewPort(true); // 实现全屏
m_webView.getSettings().setLoadWithOverviewMode(true); // 实现全屏
m_webView.loadUrl(url); // 打开相应url
m_webView.requestFocus(); // 获取焦点
m_webView.setWebViewClient(new WebViewClient(){ // 新建一个WebViewClient,重载处理函数
public boolean shouldOverrideUrlLoading(WebView view, String l) {
if (l.indexOf(“回调也”) >= 0) { // 判断是否为回调页
如果是做相应处理,调回游戏中。
return true; // 不再给传来的view处理
}
if (l.indexOf(“tel:”) >= 0) { // 判断是否是手机相关
return true; // 不再给传来的view处理
}
view.loadUrl(l); // 如果都不是用view打开
return true;
}
});
rootlayout.addView(m_webView);
}
});
}
WebViewClient的shouldOverrideUrlLoading如果返回true,view将不再处理url,如果返回false的话,这由view继续处理。
定义native接口,用来在java中调入c+++
// callback
private static native void callback(String url);
在c++中实现对应接口,记得jni文章里说的,java的命名不要出现“_”,包括包名、文件名、类名,
#include “platform/android/jni/JniHelper.h”
extern “C” {
JNIEXPORT void JNICALL Java_com_domain_pack_filename_callback(JNIEnv* env, jobject self, jstring url) {
if (web_view) {
处理,保存相应数据,然后调用scheduleOnce在主线程再做处理。
web_view->scheduleOnce(schedule_selector(common::WebView::callback), 0.1f);
}
}
这里需要注意的就是c++的回调,不确定是在什么线程,一定要schedule到主线程处理。

后面调试的时候遇到问题,android 2.3.x的机器都不会调到shouldOverrideUrlLoading这个函数,可以重载public void onPageStarted(WebView view, String l,Bitmap favicon)来做判断,还可以把loading状态在这里显示出来,public void onPageFinished(WebView view, String l) 在这里结束loading状态。Bitmap需要import android.graphics.Bitmap;

最后编辑:
作者:wy182000
这个作者貌似有点懒,什么都没有留下。

留下一个回复