• 搭建环境

  • 开启c++11支持,在jni/Application.mk中添加:

      APP_CPPFLAGS += -std=c++11
      NDK_TOOLCHAIN_VERSION := 4.7
  • ../../Classes/*.cpp文件加入编译,使用

      LOCAL_SRC_FILES := main.cpp \
          $(subst jni/, , $(wildcard $(LOCAL_PATH)/../../Classes/*.c*))

    jni/Android.mk中的LOCAL_PATH := $(call my-dir)表示Android.mk文件所在的目录。

  • c++序列化可用MessagePackJsonCpp

  • 使用JNI从Java调C++

  • 集成admob


Problems

  • APP_PLATFORM android-14 is larger than android:minSdkVersion 7

    因Eclipse误把warning做error。可在jni/Application.mk添加一行:

      APP_PLATFORM := android-<minSdkVersion>    

    minSdkVersion是你在Manifest.xml中指定的最小版本号


References

  1. paralaxer: a cocos2d-x example game project
  2. Android NDK

  • 名词解释:
    • View: usually UI widgets such as a button or text field
    • ViewGroup: invisible view container that define how the child views are laid out, such as in a grid or a vertical list
    • Activity: a single screen in your app
    • Intent: runtime binding between separate components (such as two activities). An Intent can be explicit in order to start a specific component (a specific Activity instance) or implicit in order to start any component that can handle the intended action (such as “capture a photo”).
    • Bundle: a blob of key-value pairs
    • Fragment: a nested activity that can define its own layout and manage its own lifecycle
  • Layout:
    • layout_file.xml中的属性:

      • xmlns:android=xxx: 声明xml名称空间android
      • android:id="@+id/edit_message": 声明id属性,使代码中可引用它
        @: resource object, an unique integer for an resource (bitmap, layout file, string) defined in your projects’ gen/R.java file
        +: create
        id: resource type
        edit_message: resource name, other resource type can use the same name
      • 引用resource object时还可加上namespace,如android:hint="@**android:**string/edit_message",这时引用的是android.R
    • 每个layout_file.xml会被编译成一个View,可在Activity的onCreate()中load它:setContentView(R.layout.layout_file)

    • 可在layout_file.xml中定义view并赋予id:

        <Button android:id="@+id/my_button" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="@string/my_button_text" />

      然后在代码中create它:Button myButton = (Button) findViewById(R.id.my_button);

    • View的属性layout_something定义其在ViewGroup中的layout。layout_widthlayout_height是所有View都须定义的,可定义值:

      • wrap_content: tells your view to size itself to the dimensions required by its content
      • fill_parent/match_parent(rename in API Level 8): tells your view to become as big as its parent view group will allow
      • n dp: density-independent pixel units
  • Activity lifecycle:
    • Created/Started是临时状态,Resumed/Paused/Stopped是可停留状态。Resumed指正常running,Paused指失去焦点被其他组件部分遮挡,Stopped指被其他组件完全遮挡。
    • 在onDestroy()前都会调onPause()和onStop(),除非在onCreate()直接调finish()
Activity lifecycle
  • AndroidManifest.xml:

    • 所有Activity得在AndroidManifest.xml中用<activity>元素声明

    • 启动app时进入的main activity声明时需要<intent-filter>:

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
  • android版本分布

  • android icon size: 36×36 (ldpi), 48×48 (mdpi), 72×72 (hdpi), 96×96 (xhdpi)

  • 读取AndroidManifest.xml中application的meta-data:

      try {
          ApplicationInfo ai = this.getPackageManager().getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);
          String channelName = ai.metaData.getString("UMENG_CHANNEL");
          if (channelName == null) return "";
          return channelName;
      } catch (NameNotFoundException ex) {
          Log.e("META", "Can not find the application info of" + mActivity.getPackageName());
          return "";
      }

参考:

  • Xcode自带Open QuicklyCmd+Shift+O
  • 添加Code Snippet:将选中的代码段拖到右边的Code Snippet Library中,将需要被高亮替换的snippet写作<#snippet#>
  • xcode4.x给target添加外部脚本可通过:
    1. Build Phrase: Target->Build Phrases->Add Build Phrase->Add Run Script

    2. Target Dependency: Target->Add Target->External Build System,然后主target的Build Phrases->Target Dependencies中添上它,这个target的Info->External Build Tool Configuration可如下:

       Build Tools: /bin/sh
         Arguments: ./TPupdate.sh
         Directory: ${PROJECT_DIR}/Assets/scripts/
       pass build settins in environment    
  • 给已有项目添加UnitTests,参见Adding Unit Tests to an existing iOS project with Xcode 4。在build target改名后,UnitTests的Bundle Loader项要随之更新。若开启了c++11,确保UnitTests和项目已有target的Build Settings中的C++ Language Dialect和C++ Standard Library设得一样。
  • Method Completion:type - or +, begin typing method name, omit return value
  • XCode6中可用// MARK: 代替#pragma mark,还可用// TODO:// FIXME:

Debug

  • Breakpoint Navigator (cmd+6)的左下方‘+’ -> Add Exception Breakpoint在异常抛出前暂停,当crash在main.m时开启调试

  • Edit Schema -> Diagnostics -> Enabel Zombie Objects,使引用计数为0的对象只标记不释放,当EXC_BAD_ACCESS时开启调试

  • 在代码栏左侧点击添加的breakpoint上右键 -> edit,添加条件后得到conditional breakpoint

  • 可给Breakpoint选择Action:Debugger Command,并勾上Automatically continue after evaluating,使用格式:po object

  • gdb里可用po (print object) 打印对象,po跟NSLog一样调用对象的description方法

    • 给类实现方法- (NSString *)debugDescription;,可在gdb时用po打印或Breakpoint时Log Message输出
    • UIView有方法- (NSString *)recursiveDescription;,可在gdb时输出view的层次结构
  • Xcode5.1+可以给custom object定义- (id)debugQuickLookObject;方法,以在debug quick look时查看

  • 可以在instrument的Timer Profiler里测试background fetch

Simulator

  • Double High Status Bar:测试是否对status bar的高度变化正确响应
  • Color Blended Layers:绿色表示opaque,红色表示含alpha。尽量减少红色以提高性能(尤其是scrolling list中红色)

Launch Arguments & Environment Variables

设置运行参数和环境变量:Edit Scheme -> Run [AppName].app -> Arguments,调试时两者作用相同。设置运行参数,如-NSDoubleLocalizedStrings YES;设置环境变量,则设置Name和Value,如NSZombieEnabled(Name)和YES(Value)

Localization

  • -NSDoubleLocalizedStrings YES:将字符串长度double以测试长标签
  • -NSShowNonLocalizedStrings YES:将无法localized的串以全大写显示,同时有log输出
  • -AppleLanguages (zh):不用再跑设置中更改语言,可同时再设置AppleLocale zh-Hans

Core Data

  • -com.apple.CoreData.SQLDebug 3:输出debug信息,值可设为1到3(1最简略,3最详细)
  • -com.apple.CoreData.SyntaxColoredLogging YES:彩色log
  • -com.apple.CoreData.MigrationDebug:输出migration的debug信息

Tool


Instruments

Time Profiling

  • 选中Record Waiting Threads时,Sample PerspectiveRunning Sample Times以避免显示太多idle时间
  • drag: apply a time range filter, shift+drag: zoom in, ctrl+drag: zoom out

References

  • CCRenderTexture内部使用一个sprite来显示texture,如position、anchorPoint、contentSize等属性通过这个sprite获得,CCRenderTexture自身作为一个容器不设置这些值。

  • CCTouchDispatcher处理touch事件按照priority值从小到大,与zOrder值无关。

  • 背景图片重复,要确保图片长宽是2的幂:

      ccTexParams tp = { GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT };
      [backgroundPattern.texture setTexParameters:&params];
  • CocosBuilder的tutorial

  • 后台运行cocos2d

    ios5的multitask只支持audio、location update、voip,通过播放无声audio让cocos2d后台运行:

    1. 在Info.plist中Application does not run in background设为YESRequired background modes添加App plays audio
    2. 使用MTAudioPlayer(参见这里)后台播放音乐,其主要是设置audio session category为kAudioSessionCategory_MediaPlayback

    cocos2d还要[CCDirector setDirectorType:kCCDirectorTypeDefault];,若用默认的kCCDirectorTypeDisplayLink则锁屏尚可执行但屏幕一关闭就暂停。

  • 看项目是否开启ARC:Build Settings->Apple LLVM compiler->ObjC++ ARC
    没ARC项目的个别文件开ARC:设Build Phases->Compile Sources->Compiler Flag-fobjc-arc
    开ARC项目的个别文件关ARC:设Compiler Flag-fno-objc-arc

  • 添加push通知:

    1. 按照tutorial,开启App ID中的push功能(若无CSR文件则用钥匙串访问生成),下载安装生成的ssl证书并导出p12文件。然后生成新的Provisioning Profile并下载安装。

    2. 将p12文件传到ParseUrban Airship

    3. 在AppDelegate的application:didFinishLaunchingWithOptions:里:

       [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
        (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

      然后在application:didRegisterForRemoteNotificationsWithDeviceToken:使用Orbiter

    4. 只能在设备上测试

  • 使用umeng的错误分析:

    1. 在Xcode中Product->Archive->Distribute->Export as Xcode Archive
    2. 将导出的xxx.xcarchive中Products/Applications/xxx.app和dSYMs/xxx.app.dSYM拷到一个目录下
    3. 在命令行输入atos -arch armv7 -o xxx.app/xxx,输入umeng错误日志中的地址0xaddress就可显示对应的源码行

Extenstons


References

  1. Ray Wenderlich

  • 画图步骤:1. enable state => 2. bind data => 3. glDrawArrays/glDrawElements

    1和2对应为:

      vertex: glEnableClientState(GL_VERTEX_ARRAY) <-> glVertexPointer
      color: glEnableClientState(GL_COLOR_ARRAY) <-> glColorPointer
      texCoord: glEnableClientState(GL_TEXTURE_COORD_ARRAY) <-> glTexCoordPointer
    
      texture: glEnable(GL_TEXTURE_2D) <-> glBindTexture
  • glBlendFunc(srcFactor, dstFactor):srcFactor指当前正画的图要乘上的因子,dst指已在frame中的图要乘上的因子 > online tool

用过的几个blendFunc:

  • GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA: 图片叠加,本层图片透明的部分显露下层图片
  • GL_DST_ALPHA, GL_ZERO: 用下层图片alpha通道来mask本层图片
  • GL_DST_COLOR, GL_ZERO: 本层常用灰度图去mask下层图片

shader在GPU的多核中并行执行,vertex shader每个图元顶点执行一次,fragment shader每个图元像素执行一次

Shader的语法

OpenGL Shading Language是C的子集,稍有扩展

Storage Qualifier

  • attribute: vertex shader的输入,gles =(per-vertex data)=> vertex shader
  • varying: vertex shader的输出、被插值后变成fragment shader的输入,vertex shader =(per-vrtex data)=…=(interpolated data)=> fragment shader
    Only those varying variables statically used (i.e. read) in the fragment shader must be declared in the vertex shader; declaring superfluous varying variables in the vertex shader is permissible.
  • uniform: vertex shader和fragment shader的输入,global shared readonly data
  • const: local variables & function parameters can only use const storage qualifier
  • <none, default>: function return types & structure fields do not use storage qualifiers

Parameter Qualifier

  • <none, default>/inoutinout

Precision Qualifier

  • highp: ~float32、mediump: ~float16、lowp: ~int10

  • precision precision-qualifier type; // 指定某类型的默认precision

    fragment shader中没有自动声明默认precision,vertex shader中自动声明了默认precision

Build-in Varible

特定于vertex shader的输出变量:

high         vec4 gl_Position; // should be written to
medium float gl_PointSize;     // may be written to

特定于fragment shader的变量:

medium vec4 gl_FragColor;    // 用gl_FragColor,gl_FragData[0]因兼容性原因还存在
mediup vec4 gl_FragCoord;    // 由vertex shader插值生成的(x,y,z,1/w),readonly
       bool gl_FrontFacing;  // 某surface是否是正面,readonly
medium vec2 gl_PointCoord;   // 只当本fragment位于某点(a point primitive)内时有效,
                             // (x,y)表示本fragment在该点内的相对位置,x,y在[0,1]间,readonly

Build-in Function

三角函数、指数对数、常用函数

  • dot: vector dot product, cross: vector dot product
  • *: vector component-wise multiply || matrix linear algebraic matrix multiply
  • matrixCompMult: matrix component-wise multiplication

Misc

  • mat2mat3mat4: column major matrix,先列后行

Shader的用法

  1. 编译glProgram:将vertex shader和fragment shader编译、链接得到glProgram
  2. 传入数据:获得shader中变量的location,向这个location传入数据
  3. 画图:glDrawArrays或glDrawElements

2.1 传入uniform数据

  1. glGetUniformLocation拿到location
  2. glUniform/glUniformMatrix向location传入数据

2.2 传入attribute数据

  1. glGetAttribLocation拿到location,或者在glProgram链接之前已经glBindAttribLocation设置过location,然后glEnableVertexAttribArray激活这个location
  2. glVertexAttribPointer向location传入数据在某结构中的偏移

若传入的数据量较大,可使用FBO(Frame Buffer Object)。这样就把数据拷到GPU,每次draw时从GPU取数据,避免每次draw时从CPU=>GPU的数据拷贝。

  • 使用FBO+glDrawArrays时第2步要改成:
    1. 准备数据:用glBufferDataGL_ARRAY_BUFFER填上数据,GL_ARRAY_BUFFER已用glBindBuffer绑定到某个buffer(GLuint)
    2. glVertexAttribPointer向location数据在GL_ARRAY_BUFFER中的偏移,GL_ARRAY_BUFFER已用glBindBuffer绑定到数据buffer

若用glDrawElements画图,还需传入顶点索引,要将上述GL_ARRAY_BUFFER换成GL_ELEMENT_ARRAY_BUFFER

2.3 传texture时需要传texture data和texture coord

  • 传texture data这一uniform(sample2D类型):
    1. glGetUniformLocation拿到location
    2. 准备数据:用glTexImage2DGL_TEXTURE_2D填上数据。GL_TEXTURE_2D已glActiveTexture激活某个索引值(默认是0,GL_TEXTURE0),并glBindTexture绑定某个buffer(GLuint)到该索引值,且设置好texture params。
    3. glUniform向location传入GL_TEXTURE_2D某个buffer的索引值(默认传0)。GL_TEXTURE_2D需glActiveTexture激活该索引值(默认是0,GL_TEXTURE0),并glBindTexture绑定某个buffer(GLuint)到该索引值。
  • 传texture coord这一attribute:同attribute用法

References

  1. Khronos的《OpenGL ES Shading Language》

Creating

  • git clone /path/to/repo [dst-dir] #clone远程或本地repo
    • -b <branch> #克隆某分支
    • --depth <depth> #shallow clone
  • git init #当前目录下建个叫.git的GIT_DIR,当前目录作GIT_WORK_TREE
  • git init --bare #以当前目录作GIT_DIR,没有GIT_WORK_TREE

Snapshotting

git维护3棵tree:working-dir =(add)=> index =(commit)=> history

HEAD指向当前分支的最新history,HEAD~n指向HEAD的第n个祖先,HEAD~HEAD~1指向HEAD的父节点。

  • git add file-pattern #将file加到index

  • git status -s #short output

    git status输出的第一列字母表示index相对于HEAD的状态, 第二列字母表示working-dir相对于index的状态

  • git diff #无参数,working-dir<->index

  • git diff --cached #index<->HEAD

  • git diff HEAD #working-dir<->HEAD

  • git commit #将index=>HEAD,常用git commit -am 'commit message'

  • git checkout [-- file-names] #index=>working-dir(working-dir中的新文件保持不变)

  • git checkout HEAD [-- file-names] #HEAD=>index && index=>working-dir

  • git reset [-- file-names] #HEAD=>index

  • git reset --hard [-- file-names] #HEAD=>index && index=>working-dir

  • git rm --cached # index

  • git rm #无参数,working-dir && index

  • git mv #无参数,working-dir && index

Branching & Merging

  • git branch # 列出所有branch

  • git branch branch-name #新建branch

  • git branch -f branch-name start-point #切换已有分支的起始点

  • git checkout branch-name #switch到某个已有branch

  • git checkout -b branch-name #新建个branch并switch过去

  • git branch -d branch-name #删除branch

  • git merge branch-name #将某个branch合并回当前分支

  • git log #当前branch的commit历史,含选项:

    • --oneline #一行一个
    • --graph #branch&merge关系图
    • --decorate #可显示git tag信息
  • git log branch-name #某branch的commit历史

  • git log branch1 ^branch0 #在branch1但不在branch0中的commit历史,可在branch0合并branch1前用这个命令查看哪些是来自branch1的修改

  • git tag -a annotation #打tag

  • git tag -a annotation commit-id #给某次commit补打tag

Sharing & Updating

  • git remote -v #列出所有remote repo

  • git remote add repo-allias /path/to/repo #添加远程或本地的另一个repo

  • git remote rm repo-alilas

  • git fetch repo-alias #fetch某个repo

  • git fetch --all #所有remote repo

  • git pull #git fetch && git merge

  • git push repo-alias branch-name #将本地当前分支push到repo的branch

  • git push --tags #push tags

  • git push -f #强制push

Others

  • git reflog #查看git命令的历史,然后可通过git reset HEAD@{x}撤销git命令
  • git cherry-pick commid-id # 合并某commit到当前分支

配置文件

~/.gitconfig全局配置:

1
2
3
4
5
6
7
8
9
10
11
12
# 用户信息
[user]
name = your-name
email = your-mail
# 添加别名
[alias]
st = status
co = checkout
ci = commit
br = branch
[color]
ui = true #彩色输出

push到多个remote

假设已有remote名叫githubbitbucket,用git config -e编辑配置:

[remote "origin"]
    url = git@github.com:username/somerepo.git
    url = ssh://git@bitbucket.org/username/somerepo.git

然后就可git push origin,push到这两个remote


git bisect二分法找bug

假设v2.0后某版本新引进了个bug,为找出这个引进bug的版本,可用git bisect来二分查找

  1. git bisect start
  2. 在最新的有bug版本上git bisect bad,在没bug的v2.0上git bisect good v2.0
  3. 这时git会自动checkout到中间某版本,运行测试并根据结果标记git bisect goodgit bisect bad
  4. 如此标记下去,最后git会告诉你哪个版本bug最早出现

Submodule

  • 给project添加submodule

    假设要把某repo作为子模块加入自己的project,则在project目录下:

      git submodule add /path/to/repo submodule-dir # 类似git clone,但会写.gitmodules文件
      git submodule init # 在.git/config中添加submodule信息
      git commit -am 'add submodule'
  • clone含submodule的repo

      git clone --recursive /path/to/repo dst-dir

    其等同于:

      git clone /path/to/repo dst-dir #并不更新submodule内容
      git submodule init
      git submodule update
  • 修改project的submodule

      #1. 将submodule切换到master分支
      cd submodule-dir
      git checkout master 
      #2. 修改submodule,然后提交
      git commit -am 'update submodule'
      git push
      #3. 回project目录,提交新的submodule commit id
      cd project
      git commit -am 'update submodule commit id'
      git push
  • 更新submodule

      git pull #并不更新submodule内容
      #git submodule init #确保曾运行过
      git submodule foreach git pull #不可用git submodule update
      git commit -am 'update submodules'
  • 删除submodule

      #1. 删除submodule-dir
      #2. 删除.gitmodules中的配置
      #3. 删除.git/config中的配置
      #4. git commit -am 'delete submodule'

rewriting history

  • git commit --amend

    可替换最近一次commit,用来修改最近一次注释、修改最近一次提交的文件、添加遗漏的文件、删除多余的文件等

  • git rebase -i HEAD~n

    可以以交互方式重排前n个commit。squash和fixup都把改动合并到前一条,squash保留comment,fixup不留comment。

  • rebase on top of master

    我们fork了master后,master又有了新更新,要合并这些更新:

      # Point our *upstream* remote to the original fork
      git remote add upstream https://github.com/thoughtbot/factory_girl.git
    
      # Fetch latest commits from *upstream* (the original fork)
      git fetch upstream
    
      # Checkout our feature branch
      git checkout feature
    
      # Reapply it onto upstream's master
      git rebase upstream/master
    
      # Fix conflicts (may use *git mergetool*), then *git rebase --continue*, repeat until done
      # Push to our fork
      git push --force origin feature

重用ssh连接

为加快git pull的速度,编辑~/.ssh/config

ControlMaster auto
ControlPath /tmp/%r@%h:%p
ControlPersist yes

GitHub

  • Account settings > SSH Keys中添加本机的ssh key后,要git clone git@github.com:username/username.github.com.git这种地址key才有效

References

  1. Git Simple Guide
  2. gitref.org
  3. Git Submodule使用完整教程
  4. Learn Git Branching
  5. Git branching model
  6. Speed Up Git (5x to 50x)
  7. Git Interactive Rebase, Squash, Amend and Other Ways of Rewriting History