Cocos2d-x v3.16+fabricでCrashlyticsをインストールする

# 概要
Cocos2d-x v3.16 で Crashlytics を利用する手順を記載しています。
Crashlyticsとは、簡単にいうとクラッシュレポートを送信してくれるサービスです。無料で使えます。
(備忘のメモとして記載してるんで、以降は説明とかあやふやだったりします。ご了承下さい)

## 動作環境
* Mac OS X
* cocos2d-x v3.16
* XCode 9.2
* Android Studio 3.1
* Android NDK r13b

# fabricの登録
https://www.fabric.io
普通に登録します。

# iOS側のインストール
fabricに登録したら、最初こんなシンプルな画面が表示されるため、まずはAppleをクリック。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/923b2b18-3ab7-60a1-92fe-5f2b6ad4c820.png)

すると、FabricのAppをインストールさせられる。言われた通りにやっていく。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/e6cfa0f9-cd24-e9f0-ede1-de52968dfaaf.png)

Crashlyticsをインストールしたいプロジェクトを選択する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/10506a0c-ded9-e3d2-b768-81be117b45ea.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/86638f43-eea4-34aa-cd91-17087f619172.png)

手順を続けると、こんな画面になる。書いてる通りに行う。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/ed568179-dfd3-1cfb-4e9d-b3a30ddfba9f.png)

1. Add a Run Script Build Phase の(?) ボタンを押すと画像つきで説明してくれる(^^)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/d21ba4cd-05e9-f9b6-e27b-6be8750bcf93.png)

それでXCodeのプロジェクトをビルドすると、こうなる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/3240ee35-f9f9-d388-deef-0c023e5126f6.png)

指示されてるとおり、ドラッグアンドドロップする。
また、その際にでてくるダイアログでは、Copy items if needed のチェックははずす

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/b61fa7e8-2dc1-dc01-dfd8-af366065ad8a.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/4b470e04-4e1c-b957-5d84-b3f75cf42c39.png)

うまくできたら（？）、こんな画面になるので言われたとおりに実装する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/35722d0e-a7b5-39b2-f941-824a73e94df7.png)

```objective_c
// AppController.mm

#import "AppController.h"
#import "cocos2d.h"
#import "AppDelegate.h"
#import <Fabric/Fabric.h> // 追加
#import <Crashlytics/Crashlytics.h> // 追加
#import "RootViewController.h"

(省略)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
　　　　　　　　// 追加
    [Fabric with:@[[Crashlytics class]]];
    
    cocos2d::Application *app = cocos2d::Application::getInstance();
    
    // Initialize the GLView attributes
    app->initGLContextAttrs();
    cocos2d::GLViewImpl::convertAttrs();

(省略)
```

C++の行数とかを表示させる場合、Build Settingsで以下をしたらいいらしい。

```
"Strip Debug Symbols During Copy" -> NO
"Strip Linked Product" -> NO
"Use Separate Strip" -> NO
```
`Use Separate Strip` がみつからない。。。とりあえず無視。

あとは、一度 *⌘R* で実行したら完了らしい。
ブラウザからfabricをみてみると、ダッシュボードができてる。

## iOSの動作確認(クラッシュさせてみる)

まずはCrashlyticsで書かれた方法でクラッシュさせてみる。

https://docs.fabric.io/apple/crashlytics/test-crash.html#

```objc
// NativeLauncher.hpp

class NativeLauncher {
public:
    static void testCrash();
};

// NativeLauncher.mm
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Crashlytics/Crashlytics.h>

void NativeLauncher::testCrash() {
    [CrashlyticsKit crash];
}

```

上記をC++上から任意の箇所で呼び出してみる。
XCodeのデバッガで止まっちゃうとだめなので、一度デバッガをとめて、シミュレータなどから直接アプリを起動してクラッシュさせると、次のアプリ起動時にクラッシュレポートが送信される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/6c439803-7474-545b-a958-5cfa1e3df673.png)

ちゃんとC++側のLineまで表示されててビビる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/c5a715b0-b936-ed0a-1c94-abc75978604d.png)

C++側でstd::runtime_errorなどを起こしてクラッシュさせたらこんな感じ。
Reasonはわかるけど、スタックトレースはあまり役に立たない。
runtime_errorでエラーハンドリングする場合は理由をちゃんと記載しないといけない。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/b110ce4b-12c8-917e-3024-1f0fc77d302a.png)

最後、ぬるぽのようなクラッシュのケース。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/abbd716b-8323-d611-ce36-5eb5dc158e58.png)

ちゃんとどこでぬるぽ起きてるか見れる。。。
無意味にruntime_errorとかは使わない方がいいのかな。。。？

# Android側のインストール

Androidの場合、なぜか Android Studio2系だとダメだった。
ダメではないんだけど、以下みたいなゴミしかとれなかったからダメだと思う。
(たぶんぼくの設定が何か足りなかったからだと思うけど。。)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/ba7fc17a-d74a-4ae9-c8ce-b6bdfe0e4c31.png)

そのため、Android Studio 3.1にアップグレードし、かつAndroid NDKも r13bに変更した。
(最新のAndroid NDKを使わないのは、cocos2d-xのコミュニティでr13bが安定してるみたいな話しがあったため)

fabricがちょっとわかりづらいけど、アプリの追加はここに書いてる。
(なぜ最初とUIが違うんだろうとかは考えない)

https://www.fabric.io/kits/android/crashlytics/install

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/f0739d02-af0b-2c1f-b44d-ccdfac7d33eb.png)

すると、プラグインを使えみたいなのが見れる。
https://www.fabric.io/downloads/android-studio

これをインストールすればいいらしい。星が少ないのが気になるけど深くは考えない。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/f7d211c7-abf7-7676-8e30-46b0b66579d5.png)

インストール後、fabricっぽいアイコンがでてるので押下して進めていく。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/ca642dda-8b97-e993-a2b8-508d82fbaf23.png)

進め方はiOSの時と同じ。
書かれてる通りに設定を行っていくと罠にハマるため以下のように設定。

proj.android-studio/build.gradle

```gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
        maven { url 'https://maven.fabric.io/public' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.1' // 最新にする
        classpath 'io.fabric.tools:gradle:1.+'
        // 下に何か書いてるけど気にしない
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}
```

proj.android-studio/app/build.gradle

```gradle
import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'

// 省略
android {
   // 省略
   buildToolsVersion '27.0.3' // Android Studio 3.1を使うため。その他のbuild.gradleのbuildToolsVersionも同じように合わせる
   // 省略
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':libcocos2dx')
    // 追加
    compile('com.crashlytics.sdk.android:crashlytics:2.9.1@aar') {
        transitive = true;
    }
    // 追加
    compile('com.crashlytics.sdk.android:crashlytics-ndk:2.0.2@aar') {
        transitive = true;
    }
}
// 追加
crashlytics {
    enableNdk true
    manifestPath 'AndroidManifest.xml'
}
```

clashlyticsの `androidNdkOut` と `androidNdkLibsOut` を入れろみたいなことを言われるけど、入れなくていいみたい。

AndroidManifest.xml

```xml
<?xml version='1.0' encoding='UTF-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jp.xxxxx.xxxxxxx" android:installLocation="auto">
    <uses-feature android:glEsVersion="0x00020000" />
    <application hardwareAccelerated="true" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name">
        <meta-data android:name="android.app.lib_name" android:value="MyGame" />
       <!- 追加-->
        <meta-data android:name="io.fabric.ApiKey" android:value="XXXXXX" />
       <!--省略-->
    </application>
    <uses-permission android:name="android.permission.INTERNET" /> <!--なければ追加-->
    <!--以下略-->
```

fabricのを使うには、AndroidのminSdkVersionが14以上じゃないとダメみたい。
というわけで、そこも修正する。

proj.android-studio/gradle.properties

```properties
PROP_COMPILE_SDK_VERSION=22
PROP_MIN_SDK_VERSION=14
PROP_TARGET_SDK_VERSION=22
PROP_APP_PLATFORM=10
PROP_APP_ABI=armeabi:x86
```

COMPILE_SDK_VERSIONとTARGET_SDK_VERSIONは一緒にしないとなぜかビルド時にぬるぽが発生する。

また、Android Studio 3.1で動かすためにgradleもバージョンアップさせる。

gradle-wrapper.properties

```properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
```

一度これでGradle Syncさせてみる。
通ったら、次はAppActivity.javaの修正を行う。

AppActivity.java

```java
public class AppActivity extends Cocos2dxActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.setEnableVirtualButton(false);
        super.onCreate(savedInstanceState);
        // Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
        if (!isTaskRoot()) {
            // Android launched another instance of the root activity into an existing task
            //  so just quietly finish and go away, dropping the user back into the activity
            //  at the top of the stack (ie: the last state of this task)
            // Don't need to finish it again since it's finished in super.onCreate .
            return;
        }
        // DO OTHER INITIALIZATION BELOW
        // 追加
        Fabric.with(this, new Crashlytics(), new CrashlyticsNdk());
    }
    // 以下略
```


最後、以下を実行する。
なお、これはAndroid版でビルドする際毎回やらないといけないらしい。

```bash
$ ./gradlew crashlyticsUploadSymbolsDebug 
// リリース版の場合
$ ./gradlew crashlyticsUploadSymbolsRelease 
```

うまくいったら、普通にAndroid Studio から ▶ ボタンで起動する。
すると、Fabricにプロジェクトが登録される。

## 動作確認

また意図的にC++側でぬるぽが発生するようにしてみて、実行してみる。

```c++
// 実行箇所
Sprite* spr = nullptr;
spr->setPosition(1,2); // ここでクラッシュするはず
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/6f3d7e01-b01f-8ae9-e7cc-6fb054391c95.png)

とれた！

ちなみに、ラムダの中でクラッシュさせると、以下のようなゴミに近いものしかとれない。
だから、あまり使わないか使う前にログを出したりとかした方がよさげ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/163629/82f1f9f6-504f-cb41-0051-4a478e4f1969.png)

とりあえず、あまり情報がない中で両方できたから満足。