Lu Guanqun

记点心得,写些技术,发发牢骚,您且看着

Xcode 时不时有些不靠谱

用的多了,明显地觉察到用起来不是顺畅,时不时的给你些小问题。今天就来八一八这个xcode的事情。

xcode的CPU使用率突然飙升。这个时候就会明显地感觉到系统的卡顿。用activity monitor一看,发现xcode的使用率到了300多。风扇在狂转,之后xcode异常退出…… 这个已经遇到了好多次,我大致估计可能是内部做源码索引的时候太耗资源了。也有时候是发现它想自动提示一个东西,但是半天出不来,然后卡死…… 不过我每次遇到这样的问题,都是很善意的发送错误日志给apple,希望他们能在后面的版本中解决掉。

对资源的管理有问题。我的一个游戏工程文件,我明明先删除了一个目录,然后用拖拽进来一个新的,但神奇的发现原来的目录也被拷贝到app里面去了,不管我如何clean build,也同样如此,simulator和真机都有如此的问题,看编译的脚本也没有看到把这个原来的目录复制进去的操作。奇怪了半天,我把xcode关掉,重启,竟然好了,我估计是有内部的cache。但不管怎么说,遇到这样的情况,让人觉得不可靠。

查看一个软件都安装了些啥

经常需要用到 Red Hat 系的 Linux 系统和 Debian 系的系统。市场在安装了一个软件包之后不知道实际安装了些什么。这个时候就需要我们来查询一下了,在这两个系统分别有不同的命令:

对于 Red Hat 的系统可以使用:

1
sudo rpm -ql <package-name>

对于 Debian 的系统可以使用:

1
sudo dpkg -L <package-name>

在低端 VPS 编译出错

今天在自己的 VPS 上编译点小东西,但是竟然不断的出现 gcc: internal error 的事情,起初还以为自己安装的系统有问题,但后来转念一想,应该是自己的 VPS 的内存太小了,只有 512 M,而且已经用掉一部分了,并且连 swap 分区也没有挂,那么当遇到需要分配内存的时候,就直接失败了,或者直接被 OOM kill 掉了。

我一升级到 1024M,马上就没有这个问题了。不错!Linode 现在还会自动把 512 的升级成 1024 的。

整合 Umeng Sdk 遇到的一些问题

本来想整合 umeng 的 SDK 来对自己的应用进行分析,但是在整合的过程中遇到了一些问题,现记录如下:

首先,默认的 umeng SDK 是基于 objective-c 的,这就导致不能直接在 cocos2d-x 中使用。在 cpp 文件中不能调用 objective-c,一定要转成 mm 结尾的。如果这样的话,那么在之后需要加入记录事件的地方就很麻烦了。但好消息是,从 2.1.3 版本开始,cocos2d-x 中多加了一个 plugin 目录,可以帮助我们处理这些事情,plugin 的概念很广,我这里暂时仅仅限于分析的 SDK,它还包括 IAP 的东西。

所以第一步我需要做的就是将 plugin 目录下面的 protocols 和 plugins/umeng 给加到我的工程里面来。这个事情还是很好办的。就像下面的这个图的样子,其中MyApplication 包含MyLibrary

对应的xcode工程文件都在proj.ios目录下面。

之后我们需要选择我们的主应用程序,设置 target dependency 就如图中显示的那样。

依赖设置好以后,我们就需要将连接的库文件也包含进来。这个在图中的Link Binary with Libraries中。

这才是万里长征的第一步,接下来我们需要加入实际的代码,一般而言,我们需要在自己的AppDelegate.cpp 中加入如下的代码:

1
2
3
4
5
6
PluginProtocol *plugin = PluginManager::getInstance()->loadPlugin("AnalyticsUmeng");
g_analytics = dynamic_cast<ProtocolAnalytics*>(plugin);

g_analytics->setDebugMode(true);
g_analytics->setCaptureUncaughtException(true);
g_analytics->startSession(APPKEY);

g_analytics是个全局变量,声明啥的就请自己脑补吧。当然可以更优雅的来个singleton,这个就看自己的个人品味啦。

那么这样就可以了吗?有没有问题啊?

实际遇到的问题是发现g_analytics为空,也就是说loadPlugin()没有成功。于是接着代码找线索,发现原来它是利用 AnalyticsUmeng 的一个静态类成员变量来将 plugin 串接起来,放到一个 map 中去,但不知道什么原因,由于我在代码中没有直接使用 AnalyticsUmeng 这个类,libPluginUmeng.a竟然没有被链接进去,从而导致出错。一度我还以为是全局变量的初始化顺序导致的错误。知道这个原因之后,我甚至不链接这个库,竟然还可以编译,链接通过,怪哉。不过解决方案也很简单,就是显示的调用该类即可,比如在上面的代码上加入如下代码:

1
2
AnalyticsUmeng *umeng = dynamic_cast<AnalyticsUmeng*>(g_analytics);
umeng->setDefaultReportPolicy(AnalyticsUmeng::BATCH_AT_LAUNCH);

好,问题还没有结束,之后我发现还是会报错,loadPlugin()返回NULL。

进一步分析,定位到在 Protocol 的项目中,利用到了这样的一句话:id obj = [[NSClassFromName(name) alloc] init]。但结果 obj 一直返回 nil。这里的 name 是正确的 UmengWrapper

真是百思不得其解,一度还怀疑是不是库又没有链接上,从而导致 objective-c 无法在动态环境下获得我们在另外一个项目中的类。

最后的最后,还是靠我们万能的 stackoverflow 解决了这个问题,原来是我们的 cocos2d-x 主要是 cpp 的代码,它在链接静态库的时候没有默认加上 -ObjC 的这个选项,(需要加到Other Linker Flags),从而导致 objective-c 的一些动态特性没办法使用。这个文章的 stackoverflow 链接 在此。如果你想用到静态库的 category 特性,那么也需要将这个 flag 打开,具体的解释在苹果官方的文档里

故事到此就完美的结束了吗?王子和公主幸福在一起了吗?古语有云,一波三折嘛。。。

调试又直接出错,出错的位置在 AVAudioPlayer 中,一圈搜索下来,貌似是由于它在播放音乐文件的时候会去查它的 tag,但是很可惜,没有 tag,内部出 exception,同时,由于我在前面的调试过程把捕获所有的exception打开了,所以一到这个地方就直接给我停住了,出现了比较奇怪的样子。解决方案也很简单,去掉捕获所有异常的选项,或者给你的 mp3 加上正确的 meta data 信息。

至此,终于完成了集成工作,可以在 umeng 的后台看到自己调试的信息了。 :)

将 hd.png 的图片弄成 .png

现在有这样的一个需求,需要将资源文件中的-hd.png转化成对应的.png文件。因为在新的 cocos2dx 中,已经不再使用后缀的形式的来搜索对应的高清资源文件,而是需要我们把对应的高清文件放到一个专门的目录下面,之后我们可以通过设置资源的搜索路径来搞定。

这里,我写了一个简单的脚本,希望可以帮到大家,默认做的事情就是夺取当前目录下的所有以 png 结尾的文件,然后将 -hd.png 的文件自动重命名为 .png,如果发现有些文件没有对应的高清文件,那么就自动跳过,但是不用担心,我会把漏掉的那些文件显示在终端上,方便我们核对和进行后处理。

代码如下,我也放了一份在 github gist 上。

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
54
55
56
import os
import re

files = []
for (root, dirnames, filenames) in os.walk('.'):
    if len(filenames) != 0:
        for one in filenames:
            files.append(os.path.join(root, one))

isPng = re.compile(r'.*\.png$')
isHdPng = re.compile(r'.*-hd\.png$')

pngFiles = []
for f in files:
    if isPng.match(f):
        pngFiles.append(f)

hdPngFiles = []
for f in files:
    if isHdPng.match(f):
        hdPngFiles.append(f)

sdPngFiles = []
for f in pngFiles:
    if f not in hdPngFiles:
        sdPngFiles.append(f)

# check whether these two lists cover the same files
excludeFiles = []
for f in sdPngFiles:
    correspondingFile = re.sub(r'\.png$', r'-hd.png', f)
    if correspondingFile not in hdPngFiles:
        print f + ' doesn\'t have a corresponding hd file ' + correspondingFile
        excludeFiles.append(f)

for f in hdPngFiles:
    correspondingFile = re.sub(r'-hd\.png$', r'.png', f)
    if correspondingFile not in sdPngFiles:
        print f + ' doesn\'t have a corresponding normal file ' + correspondingFile
        excludeFiles.append(f)

print
print 'Excluded Files:'
for f in excludeFiles:
    if f in sdPngFiles:
        sdPngFiles.remove(f)
    if f in hdPngFiles:
        hdPngFiles.remove(f)
    print '  ' + f

# replace!
for f in hdPngFiles:
    correspondingFile = re.sub(r'-hd\.png$', r'.png', f)
    os.rename(f, correspondingFile)

print 'Done!'

Unity3d对于基本的移动开发免费啦

最近的消息,Unity3D 对于基本的 IOS,Android 平台发布免费啦。之前貌似都有收400美金的。国内现在也有不少公司使用 unity3d 来进行手机游戏开发。看到这个免费消息,心动是不是也要学习学习 unity3d 开发 :)

不过个人对于 3D 不是很感冒。另外是否需要使用这个游戏引擎还是取决于游戏的类型,如果只是2D的一些简单游戏,那完全不用上这个庞大的3D引擎,但是如果你希望得到的是3D的FPS类型的,那使用这个引擎就很方便了,因为它帮你做掉了很多事情。