VisualStudioでNativeActivityを使ってAPKを作ってみる - ver.01 assetsフォルダからファイルを読む

# はじめに
今回はassetsフォルダからファイルを読み込むところを作ろうと思います。
前回の開発環境をそのまま使用します。

# 前回のリンク
- [VisualStudioでNativeActivityを使ってAPKを作ってみる - ver.00 環境構築編](https://qiita.com/furui/items/42785dfda4238cb105af)

# ソリューションの構成
大きく分けて２つのプロジェクトで構成されています。

- AndroidApplecation.NativeActivity
 - ダイナミックライブラリ(soファイル)を生成するためのプロジェクト。
 - 主要なプログラムコードはこちらに配置します。

- AndroidApplecation.Packaging
 - APK内に含めるファイルを配置するプロジェクト。
 - アセット用のフォルダはこちらに配置します。

# アセットフォルダの準備
早速アセット配置用のフォルダを作成していきます。
1. 「ソリューション エクスプローラー」->「AndroidApplecation.Packaging」を右クリックし、「追加(D)」->「新しいフォルダー(D)」を選択します。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/1b7e65b9-c648-9977-ea8e-5aac6f76c204.png)

2. フォルダ名は「**assets**」にしてください。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/00a2bf38-9bbe-8d1f-a807-b950fb2fadfd.png)

3. 作成した「assets」フォルダで右クリックし、「エクスプローラーでフォルダーを開く(X)」を選択し、今回テストで使用する「**testlist.txt**」を配置して下さい。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/127d8c41-2435-5a93-715a-eba935e30ace.png)

4. 「testlist.txt」の中身は下記のようにして下さい。

```textlist.txt
abcdefghijklmnopqrstuvwxyz
```

5. プロジェクトにtestlist.txtを追加します。Visual Studioに戻り、「ソリューション エクスプローラー」->「すべてのファイルを表示」を選択します。
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/686c77d1-5288-6d60-f98c-4c787bb0576e.png)

6. 「AndroidApplecation.Packaging」->「assets」->「testlist.txt」を右クリックし、「プロジェクトに含める(J)」を選択します。
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/22c9f7d4-b1c3-c056-f3dc-c088f1909ada.png)

7. 再度「すべてのファイルを表示」を選択します。
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/e7be7fc6-6b29-7102-c66b-96e38d288472.png)

8. 「AndroidApplecation.Packaging」->「assets」以下に「testlist.txt」が追加されていることを確認します。
![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/42282791-1bf6-9fc6-7f73-fb0761583965.png)

これでassetsフォルダの準備は完了です。

# C++言語の設定
今回の開発ではC++11を使用したいと考えています。
そのためC++11を使用するための設定を行います。

1. 「ソリューション エクスプローラー」->「AndroidApplecation.NativeActivity」を右クリックし、「プロパティ(R)」を選択します。
「AndroidApplecation.NativeActivity プロパティページ」というウィンドウが立ち上がります。
![8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/0836f856-446c-8b2c-c4ff-b87807bf1266.png)

2. 「構成(C)」を「**すべての構成**」に変更し、「プラットフォーム(P)」を「**すべてのプラットフォーム**」に変更します。
その状態で「構成プロパティ」->「C/C++」->「言語」内の「C++ 言語標準」という項目を「**C++11 (-std=c++11)**」に変更します。
![9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/151602c8-617d-b53a-efb1-988e73a70b65.png)

これでプログラムを組む準備ができました。

# テキストを読み込む関数を実装
それでは早速「testlist.txt」を読み込んでみようと思います。
「ソリューション エクスプローラー」->「AndroidApplecation.Packaging」->「main.cpp」を開き、リソースを読み込む下記ソースコードを記載します。

```cpp:main.cpp
#include <assert.h>

/// <summary>
/// リソースを読み込む
/// </summary>
/// <param name="manager">アセットマネージャー</param>
/// <param name="filePath">ファイルパス</param>
/// <param name="fileSize">ファイルサイズ</param>
/// <returns>成功：読み込んだデータ</returns>
/// <returns>失敗：nullptr</returns>
void* LoadResource(AAssetManager* manager, const char* filePath, unsigned int* fileSize)
{
    AAsset* asset = AAssetManager_open(manager, filePath, AASSET_MODE_BUFFER);
    assert(asset);

    void* data = nullptr;
    if (asset)
    {
        size_t size = AAsset_getLength(asset);
        data = malloc(size);

        // データを読み込む
        AAsset_read(asset, data, size);
        AAsset_close(asset);

        if (fileSize)
        {
            *fileSize = static_cast<unsigned int>(size);
        }
    }

    return data;
}
```

AndroidNDKには、AAssetManagerというassetsフォルダにアクセスするための仕組みが用意されています。
今回はこの仕組みを使ってファイルアクセスの部分を作ってきます。
簡単にそれぞれの用途を説明しますと、

- AAssetManager_open関数：ファイルを開く
- AAsset_getLength関数：ファイルサイズを取得する
- AAsset_read関数：ファイルをメモリに読み込む
- AAsset_close関数：ファイルを閉じる

となります。

# logcatを表示
LoadResource関数を実際に使ってみる前に、動作確認するための準備をします。
今回は簡単に確認するためにログを出力して行こうと思いますので、「logcat」を表示していきます。
「ツール(T)」->「Android ツール」->「logcat」を選択するだけです。
![10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/dc3fcdd1-ddfa-b91f-d537-d036b2e8f3d9.png)
これで準備完了です。

# LoadResource関数を使ってみる
それでは実際にLoadResource関数を使って実際にリソースを読み込んでテキストの文字列をlogcatに出力してみようと思います。

android_main関数がmain.cppにあると思いますので、そちらに記載していきます。
下記の記載を参考にソースコードを追記してみて下さい。

```cpp:main.cpp(一部抜粋)
/**
* これは、android_native_app_glue を使用しているネイティブ アプリケーション
* のメイン エントリ ポイントです。それ自体のスレッドでイベント ループによって実行され、
* 入力イベントを受け取ったり他の操作を実行したりします。
*/
void android_main(struct android_app* state) {

	/* 省略 */

	// ループはスタッフによる開始を待っています。

    // 動作チェック before
    unsigned int fileSize = 0;
    void* fileData = LoadResource(state->activity->assetManager, "textlist.txt", &fileSize);
    if (fileData)
    {
        char textStr[fileSize + 1];
        strncpy(textStr, (const char*)fileData, fileSize);
        textStr[fileSize] = '\0';
        LOGI("%s", textStr);
    }
    free(fileData);
    // 動作チェック after

    while (1) {
        /* 省略 */
    }
}
```

これであとは実行するだけです。

# 結果
logcat上にtestlist.txtに記載されている内容が表示されたでしょうか？
表示されていればファイル読み込みが正常に実装できたことになります。
![11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75533/c334e3f2-3ee6-769e-3730-29fcb710530d.png)

# まとめ
これでassetsフォルダ上のファイルにアクセスできるようになりました。
次回はlibpngを使って何かしら絵を表示する仕組みを実装していければと思っています。