LoginSignup
0
2

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-12-09

ygenda です。

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

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

前編の記事はこちら。

0. カスタマイズの準備

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

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

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

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

picture1.png

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

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

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

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

picture2.png

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

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

picture3.png

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

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

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

picture4.png

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

picture5.png

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

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

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

picture6.png

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

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

picture7.png

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

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

picture8.png

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

picture9.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

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

picture11.png

picture12.png

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

picture13.png

picture14.png

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

picture15.png

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

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

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

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

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

picture16.png

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

picture17.png

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

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

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

picture18.png

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

picture19.png

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

picture20.png

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

picture21.png

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

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

picture22.png

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

picture23.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

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

picture25.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

picture27.png

picture28.png

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

3. 実機での動作確認

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

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

picture29.png

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

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

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

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

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

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

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

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

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

picture30.png

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

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

なお、実行の途中で

picture31.png

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

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

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

picture32.jpg

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

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

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2