Android Studio 2.2(2.2.2)の導入(後編)

ygenda です。

Android Studio 2.2.2の導入。今回は後編です。

後編では、カスタマイズ(C言語、C++)および実機での動作確認を記します。

前編の記事はこちら。

http://qiita.com/ygenda/items/d0f9386cc764b8b441dd

# 0. カスタマイズの準備

カスタマイズにあたり、まずはプログラム名(ライブラリ名)を決めましょう。自由に命名してかまいません。

本記事ではC言語編では「sample」、C++編では「cpp_sample」にしました。

# 1. カスタマイズ(C言語編)

まずは、C言語編のカスタマイズ手順をまとめました。ベースは、前編の最終状態のものです。

![picture1.png](https://qiita-image-store.s3.amazonaws.com/0/149544/e90d720b-f185-ea0a-342c-48425f46f30f.png)

最初にMainActivity.javaを編集します。

まずは最後のSystem.loadLibrary()の引数部分を修正します。今回のプログラム名を sample と決めたので、native-lib から sample に修正しました。

あと、C言語の関数を呼び出す関数名を変更し、GetString()にしました。

外部参照宣言部分の関数名が赤字になっています(外部参照先が存在しないため)。これは、後で解決します。

![picture2.png](https://qiita-image-store.s3.amazonaws.com/0/149544/2e7d40a8-43ed-0381-6f0c-95ec2dd79ee3.png)

次に、Cソースファイルを格納するためのフォルダを新規作成してみます。

「app」→「src」→「main」の部分で右クリックし、「新規」→「Folder」→「JNI Folder」とたどり選択します。

![picture3.png](https://qiita-image-store.s3.amazonaws.com/0/149544/b6d0f0cb-5dad-f6e5-2409-fbd332107733.png)

新規作成するフォルダを、新たなソースファイル格納場所と認識させます。

上記の画像において、「Change Folder Location」にチェックを入れて、New Folder Locationの欄に「src/main/jni」と入れます。

終わったら「終了」をクリックします。

![picture4.png](https://qiita-image-store.s3.amazonaws.com/0/149544/4438f211-6fbd-1b1d-4a59-64e5f98cab29.png)

「app」→「src」→「main」→「jni」(今作成したフォルダ)で右クリックし、今度は「新規」→「C/C++ Source File」を選択します。

![picture5.png](https://qiita-image-store.s3.amazonaws.com/0/149544/f12b76bc-96bc-ac92-558e-ac3d8c89d12c.png)

ソースファイル名と、拡張子の入力画面です。ここでは、ソースファイル名をプログラム名と同じにすると都合がよいです。拡張子はC言語のものを作るので「.c」を選びます。

自作のヘッダファイルを作る場合は、「Create an associated header」欄にチェックを入れましょう。今回は作らないので、チェックを入れていません。

終わったら「OK」をクリックします。

![picture6.png](https://qiita-image-store.s3.amazonaws.com/0/149544/cc7ddb14-f11a-250d-dff3-ffe7c12f7b81.png)

新規作成されたsample.cの画面が表示されます。

このファイルをプロジェクトに登録するため、「Sync Now」をクリックします。

![picture7.png](https://qiita-image-store.s3.amazonaws.com/0/149544/531f6082-da13-31cf-4178-2e4adf7c16fc.png)

CMakeLists.txtの画面です。プログラム名とCソースファイル名の部分を、赤く囲った内容に修正します。

終わったら、build.gradle(app:～)のほうを変更(空白を入れて消す、という操作でOK)して、「Sync Now」をクリックしてプロジェクト内の同期を取ります。

![picture8.png](https://qiita-image-store.s3.amazonaws.com/0/149544/0c68a15b-3e6a-4675-edb2-ef38802b1ee9.png)

いよいよ、未解決だったGetString()の実体をCソースファイル内に作成します。ここで、MainActivity.javaの赤文字になっている関数名の部分をクリックしてから、「Alt」+「Enter」キーを押した後、表示された「Create function ～」をクリックします。

![picture9.png](https://qiita-image-store.s3.amazonaws.com/0/149544/bde5a037-03b9-21b8-14c2-9529cbee1fb7.png)

sample.c 内に、関数の実体が生成されました。ちなみに、この操作をした場合の関数の作成先は常に「(命名したプログラム名).c」となるようです。プログラム名とソースファイル名を合わせたほうが良い、と書いたのはこのためです。

ここで、関数名に注目してください。呼び出し側に対して、やたらと長い関数名になっていますね。

実は、JNIを介してJavaからC言語の関数を呼び出す場合、C言語側の関数名の前に以下のプレフィックスが付きます。

　"Java_[呼び出し元のJavaのパッケージ名]\_[呼び出し元のJavaのクラス名]_"

呼び出し元のJavaのパッケージ名は、MainActivity.javaの1行目のpackage の後ろに書かれているものです。ただしピリオドは識別子として使えないので、全てアンダースコア(_)に置き換える必要があります。

次に、JNIEXPORTやJNICALLなど、JNIで必要な情報が宣言されたヘッダファイル\<jni.h\>のインクルードを追加します。

最後に、関数の本体処理を記します。ここでは、strというchar型の配列に画像のような文字列を格納し、それをそのままNewStringUTFのパラメータとして渡すようにしました。

![picture10.png](https://qiita-image-store.s3.amazonaws.com/0/149544/b151405c-e4b5-e6f0-85e2-dfbd6be2c5af.png)

MainActivity.java側で赤文字表示されていたGetString()の外部参照部分が、黒文字になっていますね。

![picture11.png](https://qiita-image-store.s3.amazonaws.com/0/149544/689493bf-0fea-457d-b771-adaa52986e98.png)

![picture12.png](https://qiita-image-store.s3.amazonaws.com/0/149544/8781313e-5018-c48c-25d5-7a7d86316118.png)

あとは、呼び出し元のJava側、呼び出し先のC言語側の両方にブレークポイントを貼って、デバッグモードで実行します。

![picture13.png](https://qiita-image-store.s3.amazonaws.com/0/149544/4f70ef47-cab9-c110-2510-85ff39633947.png)

![picture14.png](https://qiita-image-store.s3.amazonaws.com/0/149544/ec06cb0d-41d6-b96e-5e11-de1913465d31.png)

両方のブレークポイントで意図通り止まることが確認でき、

![picture15.png](https://qiita-image-store.s3.amazonaws.com/0/149544/9ab163d4-3343-e246-e8cb-64ac69491c03.png)

エミュレータ上に、sample.c で作成した文字列が表示されることも確認できました。

次に、これをベースとしてC++用のカスタマイズを実施します。


# 2. カスタマイズ(C++編)

今度は、C++のカスタマイズです。

事前に、src/main 配下にあったcppフォルダは削除してから、作業を実施しました。

![picture16.png](https://qiita-image-store.s3.amazonaws.com/0/149544/9d087a49-c351-ae0e-3f74-a09b08f84b63.png)

「app」→「src」→「main」の部分で右クリックし、「新規」→「Folder」→「JNI Folder」とたどり選択します。

![picture17.png](https://qiita-image-store.s3.amazonaws.com/0/149544/155a18f3-4da2-4a9b-0e74-7dc1dd70aef4.png)

新規作成するフォルダを、新たなソースファイル格納場所と認識させます。

上記の画像において、「Change Folder Location」にチェックを入れて、New Folder Locationの欄に「src/main/cpp」と入れます。

終わったら「終了」をクリックします。これで、問題ないかと思ったのですが...

![picture18.png](https://qiita-image-store.s3.amazonaws.com/0/149544/f48cc97c-57f7-47bc-2e49-a5afd8aa73c7.png)

MainActivity.java内のSystem.loadLibrary()の引数を、sampleからcpp_sample に変更します。

![picture19.png](https://qiita-image-store.s3.amazonaws.com/0/149544/473da2cb-f1ac-5f66-706b-ab0ab83a6929.png)

CMakeLists.txt を修正します。プログラム名とC++ソースファイル名の部分を、赤丸の中のように変更します。

![picture20.png](https://qiita-image-store.s3.amazonaws.com/0/149544/3ae42a3a-18cd-9bf6-e898-d50280bf6bb5.png)

「app」→「src」→「main」→「cpp」(先ほど作成したフォルダ)で右クリックし、「新規」→「C/C++ Source File」を選択します。

![picture21.png](https://qiita-image-store.s3.amazonaws.com/0/149544/09b993be-b36e-9cab-1610-5d690adc9288.png)

ソースファイル名と、拡張子の入力画面です。ソースファイル名はプログラム名と同じ cpp_sample、拡張子はC++のものを作るので「.cpp」を選びます。

入力が終わったら「OK」をクリックします。

![picture22.png](https://qiita-image-store.s3.amazonaws.com/0/149544/1d0c8783-e2e1-e3ea-df14-befd11782484.png)

build.gradle((Project:～)でも(app:～)でもよい)を選択し、右上の「Sync Now」をクリックしてプロジェクト内の同期を取ります。

![picture23.png](https://qiita-image-store.s3.amazonaws.com/0/149544/7e334c78-3c23-0abd-f737-68a9d8de9608.png)

MainActivity.javaのGetString()の外部参照部分が赤文字になっています。1.と同様赤文字の部分をクリックしてから「Alt」+「Enter」キーを押し、表示された「Create function ～」をクリックします。

こうすれば、src/main/cpp/cpp_sample.cpp の中に関数の実体が自動作成されると思っていたのですが...実際には何故かsrc/main/jni/ の下に cpp_sample.c という名前のCソースファイルが勝手に新規作成され、そちらに関数の実体が自動作成されてしまいました。

先ほどsrc/main/cpp にフォルダ場所を変更したはずなのですが、何故か効いていないようです(問題ないかと思ったのですが...の文章が、ここにつながります。何故効かないかは、現在調査中)。

仕方がないので、今回はcpp_sample.c内に自動作成されてしまった部分を丸々コピーして、src/main/cpp/cpp_sample.cpp にペーストする措置を取りました。

![picture24.png](https://qiita-image-store.s3.amazonaws.com/0/149544/4d584cbd-b444-9dc1-69b9-8fb555acb78f.png)

ただ、これだけではC言語用の内容をコピーしたにすぎません。そこで、C++用に変更しました。

![picture25.png](https://qiita-image-store.s3.amazonaws.com/0/149544/0eec21f9-d28e-dce9-51c8-ef0bedfc8270.png)

赤丸で示した部分が、変更箇所になります。

まず、C++ということで折角だからstringクラスを使いたいところですね。そこで、\<string\>というC++の標準ヘッダファイルをインクルードします。

そして、名前空間を解決するために「using namespace std;」という一文を追加しました。

その次に、関数の本体部分の前に「extern "C"」というのを追加しました。これは「関数名に対するC++のマングルは余計なので、やらなくていいよ」という指示です。

---------------------------------
○　C++のマングルについて
C++の場合、ソースコードに記した関数名に対して、コンパイルの段階で付加情報が関数名の後ろに付きます。これは、C++にオーバーロード(同じ名前の関数を、引数の内容を変えれば複数作れる機能)が存在するためです。

付加情報というのは、関数の引数型の情報を特定するための何らかの文字列です。付加情報を関数名の後ろに付けることを「マングル」と呼びます。

ただし、JNIのインタフェースで使用する関数名については、上記のマングルは考慮されていません(マングルすると関数を呼び出せなくなる)。したがって、余計なマングルをしないようにする工夫が必要なのです。

---------------------------------

最後に、関数の本体処理部分を追加しました。

stringクラスのstrに文字列を格納して、それをNewStringUTF()の引数にしました。

後は、戻り値の部分です。C言語では、

　(*env)->NewStringUTF(env, [文字列])

を返していましたが、C++の場合だとインタフェースが少し異なっていて

　env->NewStringUTF([文字列].c_str())

を返しています。NewStringUTFの引数が1つになっている点にも、注意です。

c_str()というのはstringクラスの関数メンバで、文字列をC言語形式の型(char *)で返すためのものです。

ここまで終わったら、ブレークポイントを張ってC言語の場合同様にデバッグモードで実行します。


![picture26.png](https://qiita-image-store.s3.amazonaws.com/0/149544/347c9ea6-4417-1008-3859-d6e4d51027d5.png)

![picture27.png](https://qiita-image-store.s3.amazonaws.com/0/149544/4cf7f058-3c84-a763-afb6-7fec8222ff17.png)

![picture28.png](https://qiita-image-store.s3.amazonaws.com/0/149544/95ab2e69-7fc7-5443-4316-69eace32821f.png)

問題なくできていますね。

# 3. 実機での動作確認

導入の締めは、実機での動作確認です。

まずは、Android StudioでUSBドライバをインストールします。

![picture29.png](https://qiita-image-store.s3.amazonaws.com/0/149544/0142d999-a0ba-a379-083f-769365487099.png)

「ツール」→「Android」→「SDK Manager」を選択し、出てきた上記画面の「SDK Tools」タブの「Google USB Driver」にチェックを入れて「OK」をクリックします。

これで、USBドライバがインストールされました。

次に、実機であるAndroid端末側のセットアップです。

「設定」→「システム」の中にある「開発者向けオプション」を選択...したいところですが、それが一覧にありません。

現在のAndroid端末では、「使用者が開発者であると認識できないと、このオプションが使えない」という仕様になっているようです。

開発者と認識してもらうには、「設定」→「システム」→「端末情報」を選択し、その中にある「ビルド番号」を7～8回連続でタップします。

開発者と認識されたら「開発者向けオプション」というのが出てきます。この中の「USBデバッグ」をONにします。

これで、実機側の設定は完了です。

そして、いよいよUSBケーブルでPCと実機とを接続します。

![picture30.png](https://qiita-image-store.s3.amazonaws.com/0/149544/8573a61e-ec58-939b-6f29-f3f382cff8d8.png)

実行する際の端末選択画面において、Connected Devicesの欄に実機の情報が表示されればOKです。

あとは、これを選択して実行します。

なお、実行の途中で

![picture31.png](https://qiita-image-store.s3.amazonaws.com/0/149544/42486e4b-3d87-60d3-11fd-f599477e43d2.png)

というメッセージが出る場合があります。

このメッセージが出たら素直に「OK」をクリックして指示に従いましょう。

実行が完了したら、実機画面の表示内容を確認してみましょう。

![picture32.jpg](https://qiita-image-store.s3.amazonaws.com/0/149544/87f5f6af-fee5-0572-2b29-9afa6286176d.jpeg)

少々見づらくて申し訳ないですが、私の実機画面でもエミュレータで表示された画面が期待通りに表示されています。

以上、前編・後編と2回に分けたAndroid Studio 2.2.2の導入に関する記事でした。