人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

【超初心者向け】JavaからC++ソースを呼び出す方法 -Android Studio編 #JNI

f:id:hiro-htm877:20191027211809p:plain


 

f:id:hiro-htm877:20190601202549p:plain

 

 

 

  

 

 

 

AndroidアプリでjavaからC++のコードを呼び出すためのJNIというインターフェースを使う方法を共有します。

私自身たくさんググって5時間ぐらいかかったので、簡単にまとめます。

 

本記事のテーマ

【超初心者向け】

Android StudiojavaC++を使用したアプリ開発ができる」

・JNIインタフェースの使い方

C++Sorceファイルの追加〜Javaからの呼び出し

・例を用いて説明

 

私の使用したPCはUbuntu18.04です

Native C++プロジェクトの作成

File > New > New Project > Native C++を選択すしてプロジェクトを作成する。

※Native C++は一番下にあるのでご注意ください

(筆者は下にあることを知らず、探すのに時間がかかりました 笑)

f:id:hiro-htm877:20191027202311p:plain

 

デフォルトでapp/src/main/cpp/native-lib.cppがありますので、プロジェクト作成後、エミュレータで実行してください。「Hello from C++」と表示されると思います。

 

C++ソースファイルの追加

app/src/main/cppディレクトリを右クリックして

New > C/C++ Sorce File から追加してください。

ヘッダファイルを追加したい場合はCreate an associated headerのチェックボックスをチェックしてください。

例:「testJNI.cpp」を追加

f:id:hiro-htm877:20191027204010p:plain

JavaC++ファイルのリンク

MainActivity.java

C++ライブラリをロードします。 

System.loadLibrary("testJNI");

 ・C++の関数を呼び出します。

tv.setText(String.valueOf(stringFromJNI2("aiueo")));

 ・nativeコード(C++)の関数をjavaで使えるように宣言します。引数を与えてC++に渡すこともできます。

public native int stringFromJNI2(String str);

 

package com.example.anative;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("testJNI");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        tv.setText(String.valueOf(stringFromJNI2("aiueo")));
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public native int stringFromJNI2(String str);
} 

testJNI.cpp

cppではjavaとリンクさせるために関数名に規則があります。

java_ + ソースディレクトリからの相対パス + 関数名

・ソースディレクトリからの相対パスjavaファイルの1行目にあるpackage名を使用すると良い。

package com.example.anative;

javac/c++で方を共有するために、jstringやjint、jobjectなどの方を用います。

・JNIEnv* は VM へのポインタで、jobject は Java サイドから渡される暗黙的な this オブジェクトへのポインタです。

例:今回は引数はstringで受けとり、変数はintで返します。

#include 
#include 
extern "C" JNIEXPORT jint JNICALL
Java_com_example_anative_MainActivity_stringFromJNI2(
        JNIEnv *env,
        jobject /* this */,
        jstring str){
    std::string hello = "Hello from testJNI";
    int a;
    a = 3;
    return a;
}

 

 CMakeList.txt

・add_libraryでリンカ設定を追加します。

・target_link_librariesで出力先を設定

一番下に追加すれば良いです。

リンカの設定ですが、SHARED以外にSTATICというのもあるらしく、参考サイト「C++ でのライブラリ作成と再利用」を参考文献に載せますのでご覧ください。

add_library(testJNI SHARED testJNI.cpp)
#find_library( log-lib log)
target_link_libraries( native-lib testJNI ${log-lib})

 

 

 

 以上を実行していただければアプリ上に"3"と表示されるなんの意味もないアプリが動きます。

これを使ってjavac++を使用したアプリを作成してください!

 

 

参考文献

qiita.com

developer.android.com

developer.android.com

 

tech.hikware.com