今更ですが、cocos2d-x のプロジェクトを Android-Studio で動かしてみた。


## はじめに
モバイル端末向けアプリを作っておりまして、iOS向けは開発経験があるのですが、Android向けは未経験でした。しかし作成したアプリを広く使ってもらうためには、iOS向けだけ作っていれば良いというわけではないため、Android向けも作ることになりました。
しかしJavaを一から勉強するのもあれだし、なんといっても同じ内容のものを二つも作らなければならないということがとても面倒だったので、ネットを探してみたら cocos2d-x というフレームワークが見つかりました。

\# 実際は Unity と cocos2d-x でどちらにするか迷いましたが、3D は使わないし、オープンソースという点と言語が C++ という点で cocos2d-x にしました。

##インストール
というわけでインストール。 # リンクはページの最後。
以下をインストールしました。 # ちなみに開発環境は、macOS Sierra です。

* Xcode 9.0
* cocos2d-x v3.15.1
* Android-Studio 2.3.3
* JDK 8u144
* NDK r11

インストールは指示に従ってすればOKです。
順番は Android-Studio よりも先に JDK をインストールしておくくらいです。

Android-Studio のインストールで一緒に NDK もインストールされるのですが、最新版過ぎてダメみたいなので、サイトから NDK r11 をダウンロードして任意のフォルダにコピーして使います。

\# ちなみに任意のフォルダと言いましたが、Android-Studio をインストールしたときに SDK もインストールされますので、その側に NDK フォルダを作ってそこにコピーします。

`/Users/taro/Library/Android` の下に SDK フォルダがあるので、ここに作ります。

```
$ cd /Users/taro/Library/Android
$ cp -R <downloaded ndk_folder> ndk
```

## プロジェクト作成
プロジェクトの作成には cocos コマンドを使います。

`$ cocos new projectname -p packagename -d ./ -l cpp`

すると、./ 以下に projectname のフォルダができるので入ります。

`$ cd projectname`

一覧を見ると、 proj.xxxx というフォルダがたくさんありますが、これがそれぞれのプラットフォーム用のプロジェクトになります。

`proj.ios_mac` は iOS/Mac 用、 `proj.android-studio` は Android-Studio用 になります。今回はこの二つを使います。

ちなみに `Classes` には共通するソースコード、`Resources` は画像データなどが入ります。
`proj.android` は使用しません。

## コーディング
コーディングはそれぞれのプラットフォーム毎のプロジェクトを指定して行います。
iOS端末向けであれば、`proj.ios_mac` の中の `projectname.xcodeproj` を Xcode で起動します。
あとはいつも通りコーディングをしてシミュレーターや実機で確認します。

Android端末向けの場合は、`proj.android-studio` を Android-Studio から開きます。

## Xcode 9.x 向け修正
Xcode8.x までは特に何もしなくてよかったのですが、Xcode9.0 からはどうやら system コマンド? が使用できなくなったみたいで、修正が必要です。

　参考 → https://github.com/cocos-creator/cocos2d-x-lite/pull/828/files
　
pull request が上がっているのでそのうち cocos2d-x 本体に修正が入ると思いますが、今回は手動で修正します。
\# cocos2d-x v3.16 で修正されたみたいですね。

CCFileUtils.cpp の 1349行目から以下追加
 
```cpp:cocos2d_libs.xcodeproj/platform/CCFileUtils.cpp
// android doesn't have tfw.h
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
#include <ftw.h>
#endif
```

それから、追加後の 1427行目から以下追加

```cpp:cocos2d_libs.xcodeproj/platform/CCFileUtils.cpp
namespace {
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
    int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
        int rv = remove(fpath);
        if(rv) perror(fpath);
        return rv;
    }
#endif
}
```

追加後の 1437行目からの `bool FileUtils::removeDirectory(const std::string& path)` は中身をごっそり入れ替えましょうか。

```cpp:cocos2d_libs.xcodeproj/platform/CCFileUtils.cpp
bool FileUtils::removeDirectory(const std::string& path)
{
#if !defined(CC_TARGET_OS_TVOS)
    
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
    if(nftw(path.c_str(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS) == -1)
        return false;
    else
        return true;
#else
    std::string command = "rm -r ";
    // Path may include space.
    command += "\"" + path + "\"";
    if (system(command.c_str()) >= 0)
        return true;
    else
        return false;
#endif // CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
    
#else
    return false;
#endif // !defined(CC_TARGET_OS_TVOS)
}
```

これでエラーがなくなりますので、普通にコーディングします。

## Android-Studio 向け修正
開いてすぐの状態では `Classes` や `Resources` が見れないので、まずこれを見れるようにします。
以下を追加します。

```text:proj.android-studio/settings.gradle
include ':Classes'
project(':Classes').projectDir = new File(settingsDir, '../Classes')
include ':Resources'
project(':Resources').projectDir = new File(settingsDir, '../Resources')
```

しばらく待つか再読み込み等をすることで見れるようになります。

#### NDKへのパスの設定

次に、先ほどインストールした NDK r11 を使用するようにパスを変更します。

```text:proj.android-studio/local.properties
ndk.dir=/Users/yoshi/Library/Android/ndk
sdk.dir=/Users/yoshi/Library/Android/sdk
```

#### ビルドの設定
ビルドの設定？というよりもアプリケーション情報の設定ですか。
applicationId とか モジュール名を修正します。
\# 試してないのでわかりませんが、cocos new をしたときに -p packagename を指定した値が applicationId に入るのかもです。
\# ちなみに applicationId は '.' を含む文字列のようです。 `例） com.hoge.projectname`

\# モジュール名は重複しないようにした方がいいかもですね。プロジェクト名とか？


```text:proj.android-studio/app[projectname]/build.gradle
9行目あたり
    defaultConfig {
        applicationId "com.hoge.projectname"
        
20行目あたり（ここにモジュール名）
                    targets 'modulename'
```

もう一つ

```text:proj.android-studio/app[projectname]/AndroidManifest.xml
2行目あたり
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hoge.projectname"
    android:installLocation="auto">

14行目あたり
        <meta-data android:name="android.app.lib_name"
                   android:value="modulename" />

```

applicationId と package は同じ値にします。
targets と value も同じ値にしておきます。

#### コンパイルの設定
コンパイラを `gnustl_static` から `c++_static` に変更します。

```text:proj.android-studio/app[projectname]/jni/Application.mk
APP_STL := c++_static
```

標準では、コンパイル対象のソースを手動で追加する必要があるので、以下に書き換えて自動にします。

```text:proj.android-studio/app[projectname]/jni/Android.mk
CPP_FILES := $(shell find $(LOCAL_PATH)/../../../Classes -name *.cpp)
LOCAL_SRC_FILES := hellocpp/main.cpp
LOCAL_SRC_FILES += $(CPP_FILES:$(LOCAL_PATH)/%=%)
```

上でモジュール名を変更したので、こちらも合わせておきます。

```text:proj.android-studio/app[projectname]/jni/Android.mk
LOCAL_MODULE := modulename_shared
LOCAL_MODULE_FILENAME := libmodulename
```

以上で修正は終わりです。

## Android端末実機での動作確認
前述の修正が終わったら、メニューの `Build` から `Build APK` を実行します。
コンパイル → ビルド が行われて、APK が作成されます。
問題なく完了したら、実機をUSB接続して、再生ボタン（run [projectname]）を押すと、Select Deployment Target を聞いてくるので、実機を選んで確認します。

実機側は、USBデバッグモードを有効にしておく必要があります。
\# 有効の仕方は、`端末情報` の `ソフトウェア情報欄` を `7回タップ` する、とか (^_^)

## まとめ
Android初心者で全くわからなかったので、本当に動くのか不安でしたが、なんとか実機で動作したので一安心です。
\# Android-Studio 上でもソースコードが修正できるのでちょっと便利。


## リンク
[cocos2d-x](http://www.cocos2d-x.org)
[Android-Studio](https://developer.android.com/studio/index.html)
[JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
[NDK](https://developer.android.com/ndk/downloads/index.html)

\# NDK は android-ndk-r00-darwin-x86_64.zip の r00 を欲しいバージョンに書き換えてダウンロードしましょう。