发布于 

Cocos2d-js: 在 iOS 上运行

在我的博文 Cocos2d-js: 首次在 Mac 上面运行 这篇文章中, 介绍了 Cocos2d 相关的知识, 并且使用Cocos2dx 创建了一个 JS 的简单游戏项目.

今天跟大家分享一下, 如何在 ios 设备上面运行一个 JS 游戏项目.

该游戏项目(贪吃蛇)来自网络资源, 只供演示使用, 不提供任何关于游戏的资源.

当初的想当然

在 Mac 上面 so easy 的编译并运行了 JS 游戏, 我想在 iOS 设备上应该也很简单的就可以运行起来, 但是我发现我简单不加思考的想法, 是行不通的.

博文 Cocos2d-js: 首次在 Mac 上面运行 在 FireFox 浏览器上面可以直接运行 index.html, 但是在 Chrome 浏览器上面就没那么顺利.

想到这里, 我就受到了启发, 莫非 iOS 设备上面需要自己搭建一套 Web Server?

搭建 Web Server

既然想到了这一步, 接下来就是找方案实施了.

CocoaHTTPServer 这个可以满足我的需求, 于是, 我就直接拿来使用了.

项目中, 我使用了 Cocoapods 来管理第三方库.在 podfile 中直接添加下面的代码:

1
pod 'CocoaHTTPServer', '~> 2.3'

然后 pod install 即可.

1.在 ViewController 中导入头文件

1
2
3
4
5
6
7
8
9
10
11
#import <HTTPServer.h>
ViewController 声明部分

@interface ViewController () <WKNavigationDelegate>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) HTTPServer *localHttpServer;
@property (nonatomic, strong) WKWebViewConfiguration *wbConfig;
//用于调试的 UILabel
@property (nonatomic, strong) IBOutlet UILabel *loadingLb;
@property (nonatomic, assign) BOOL startServerSuccess;
@end

2.配置 Web Server

核心实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 - (void)_configLocalHttpServer
{
NSString *webPath = [[NSBundle mainBundle] pathForResource:@"crazySnake" ofType:nil];
_localHttpServer = [[HTTPServer alloc] init];
[_localHttpServer setType:@"_http.tcp"];

NSFileManager *fileManager = [[NSFileManager alloc] init];
NSLog(@"%@", webPath);

if (![fileManager fileExistsAtPath:webPath]) {
NSLog(@"File path error!");
}
else {
NSString *webLocalPath = webPath;
[_localHttpServer setDocumentRoot:webLocalPath];
NSLog(@"webLocalPath:%@", webLocalPath);
[self _startWebServer];
}
}
- (void)_startWebServer
{
self.loadingLb.hidden = NO;

NSError *error;
if ([_localHttpServer start:&error]) {
NSLog(@"Started HTTP Server on port %hu", [_localHttpServer listeningPort]);
self.port = [NSString stringWithFormat:@"%d", [_localHttpServer listeningPort]];

self.loadingLb.text = @"Start Server Successfully.";

_startServerSuccess = YES;
}
else {
NSLog(@"Error starting HTTP Server: %@", error);

self.loadingLb.text = @"Start Server failed.";

_startServerSuccess = NO;
}
}

_configLocalHttpServer 是配置 HTTPServer 的方法, _startWebServer 是开启 Web Server 的方法.

这样调用 _configLocalHttpServer 就可以开启在设备上面开启一个 Web Server 了.

Xcode 导入 JS 游戏项目

首先看一下我的工程和资源目录结构, 如图:

1

仔细看一下, crazySnake 这个文件夹是蓝色的, 不是黄色的.

这里特别注意, 导入这个 crazySnake 文件夹的时候, Options 一定要选择 Create folder reference.

为什么要这么做?

细心的朋友可以发现, 使用 Create folder reference 导入的文件夹, 在项目打包生成的 archive 的文件中(自己可以解压看)是可以看到 crazySnake 这个文件夹的, 如果不是这种方式, 而是使用 Create groups 方式(在 Xcode 中显示黄色), 在 archive 中是看不到 crazySnake 这个文件夹的, 而是将里面的文件打散放在 archive 的根目录下面了.

总之, 一句话, Create folder reference 方式导入的文件夹在打包后还是原来的文件夹, 不会将文件夹里面的文件打散.

试想一下, 如果多加入几个这样的目录, 都打散在根目录下面, 我们就不好管理这个文件夹里面的文件了.

配置 WKWebView

这里我使用了 WKWebView 而不是 UIWebView 作为加载 HTML 的容器.
当然, 你也可以使用 UIWebView.

主要的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)viewDidLoad
{
[super viewDidLoad];

self.navigationController.navigationBarHidden = YES;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.loadingLb.text = @"Config server...";
[self _configLocalHttpServer];
});

/// 增加的调式方法: 可以重新启动 web server.
{
SEL sel = @selector(_configLocalHttpServer);
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:sel];
[self.loadingLb addGestureRecognizer:gesture];
self.loadingLb.userInteractionEnabled = YES;
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];

// 配置 WKWebView
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

_wbConfig = [[WKWebViewConfiguration alloc] init];
self.wbConfig.userContentController = [[WKUserContentController alloc] init];

_webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:self.wbConfig];

_webView.frame = self.view.bounds;
_webView.scrollView.showsHorizontalScrollIndicator = NO;
_webView.scrollView.showsVerticalScrollIndicator = NO;

[self.view addSubview:self.webView];
self.webView.frame = self.view.bounds;
self.webView.navigationDelegate = self;

if (self.startServerSuccess) {
self.loadingLb.hidden = YES;

NSString *gameUrl = [[NSBundle mainBundle] pathForResource:@"index"
ofType:@"html"
inDirectory:@"crazySnake"];
NSURL *url = [NSURL fileURLWithPath:gameUrl];

url = [NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%@/index.html", self.port]];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
}
});
}

代码很简单, 就是使用 WKWebView 加载一个 HTML 文件并启动 Web Server.

运行项目

接下来, 就是见证奇迹的时刻了…

上面配置了 Web Server 和 加载 html 的 WKWebView, 现在可以直接运行项目看效果了.

无论你是在模拟器还是在真机上面都可以运行这个 JS 游戏项目了.

1

写在最后

上面的例子本人亲自实践过的, 给大家提供了一个实现思路, 算是抛砖引玉.

如果想做好这个模式, 还需要很多工作要做, 这里列出来给大家分享一下.

1.游戏资源包管理和下载.
2.游戏中需要和 Native 的交互逻辑.
3.数据加密.
4.移动端游戏本身的加载优化.

如果你有更好的方案和想法, 我很乐意邮件 (veryitman@126.com) 与你沟通, 非常感谢!

代码示例我放在了 GitHub, 点击 MZMWPlay 前往下载体验.


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

veryitman