JNI メソッドの使用法 -- C++ プロジェクトが Java インターフェイスにアクセスする方法 (1)

この記事では、Java インターフェイスを呼び出す C++ の機能を実現するために、Android Java で Mediaplayer 関連のインターフェイスを呼び出す例を取り上げますが、他の Java インターフェイスでも原理は同じです。

私たちのプロジェクトは C++ プロジェクトであり、このプロジェクトでは MediaPlayer を通じて音楽を再生する必要があるため、C++ で Android Java インターフェイスを呼び出す必要があります。

C++ プロジェクトでは、C++ と Java 間の通信は ndk を経由する必要があり、ndk のバージョンはプロジェクトの build.gradle ファイルで次のように構成できます。

android { 
    compileSdk 29     ndkVersion "22.1.7171670"
     buildToolsVersion = "30.0.3"

目次

Android Java で MediaPlayer を介して音楽を再生するには、次の手順を実行します。

C++ で Java インターフェイスにアクセスするにはどうすればよいですか?

MediaPlayer をインスタンス化する

setAudioStreamTypeメソッドを実行する

setDataSourceメソッドを実行する

準備メソッドを実行する

startメソッドを実行する 

いくつかの関数を理解しましょう

1.クラスの検索

2.メソッドIDの取得

3.新しいオブジェクト

4.CallVoidメソッド


Android Java で MediaPlayer を介して音楽を再生するには、次の手順を実行します。

//音楽パス

文字列パス = "/sdcard/test.wav";

// MediaPlayer をインスタンス化します
MediaPlayer mediaPlayer = new MediaPlayer();

//ストリームタイプを指定します
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

//音楽の再生パスを設定します
mediaPlayer.setDataSource(path);

C++ で Java インターフェイスにアクセスするにはどうすればよいですか?

Native プロジェクトなので、アプリケーションの起動後に android_main 関数が呼び出されます (プロジェクト内に存在する場合もあります)。この関数では、通常、JVM が初期化されます。

void android_main(struct android_app* アプリ) {
 JNIEnv* 環境; 
//Env赋值
app->アクティビティ->vm->AttachCurrentThread(&Env, nullptr); 
app->userData = &appState; 
app->onAppCmd = app_handle_cmd; 
jobject activityInstance = app->activity->clazz; 
JavaVM* jvm = アプリ->アクティビティ->vm; 
...

Env は android_main で取得でき、C++ の Java 関数はすべて Env を通じて呼び出されます。

Java が音楽を再生する方法がわかったので、それに応じて上記を C++ で実装する必要があります。C++ での実装は次のとおりです。

MediaPlayer をインスタンス化する

// MediaPlayer クラスを取得するには、クラスのパス (パッケージ名 + クラス名) が必要です
jclass MediaPlayer = Env->FindClass("android/media/MediaPlayer"); 
// パラメーターのないコンストラクター、そのメソッドは <init> です。は戻り値がないので、ここではユニバーサル
jmethodID gouzao = Env->GetMethodID(MediaPlayer, "<init>", "()V"); 
 __android_log_print(ANDROID_LOG_DEBUG, "test", "gouzao")のように書きます。 ) ; 
 //MediaPlayer クラスをインスタンス化します
jobject jobj = Env->NewObject(MediaPlayer, gouzao);

setAudioStreamTypeメソッドを実行する

//MediaPlayer の setAudioStreamType メソッド ID を取得します
jmethodID setAudioStreamType = Env->GetMethodID(MediaPlayer, "setAudioStreamType", "(I)V"); 
//ストリーム タイプを STREAM_MUSIC に設定します
jint streamType = 3; 
//MediaPlayer.setAudioStreamType を呼び出します
Env ->CallVoidMethod(jobj, setAudioStreamType, streamType); 
__android_log_print(ANDROID_LOG_DEBUG, "test", "setAudioStreamType");

setDataSourceメソッドを実行する

//MediaPlayer の setDataSource メソッド ID を取得
jmethodID setDataSource = Env->GetMethodID(MediaPlayer, "setDataSource", "(Ljava/lang/String;)V"); // ファイルの
再生パスを設定
jstring path = Env->NewStringUTF ( "/sdcard/test.wav"); 
// MediaPlayer.setDataSource 
Env->CallVoidMethod(jobj, setDataSource, path); 
__android_log_print(ANDROID_LOG_DEBUG, "test", "setDataSource");

準備メソッドを実行する

//MediaPlayer の準備メソッド ID を取得
jmethodID prepare = Env->GetMethodID(MediaPlayer, "prepare", "()V"); 
//MediaPlayer.prepare を呼び出す
Env->CallVoidMethod(jobj, prepare); 
__android_log_print(ANDROID_LOG_DEBUG, 「テスト」、「準備」);

startメソッドを実行する 

//MediaPlayer の開始メソッド ID を取得
jmethodID start = Env->GetMethodID(MediaPlayer, "start", "()V"); 
//MediaPlayer.start を呼び出す
Env->CallVoidMethod(jobj, start); 
__android_log_print(ANDROID_LOG_DEBUG, "テスト"、"開始");

AndroidManifest にストレージ関連のアクセス許可を追加し、APK をコンパイルし、APK アクセス ストレージ スペースのアクセス許可を開き、sdcard の下に music test.wav を配置して APK を開くと、音楽の再生が成功します。

このコードを通じて、C++ が Android Java インターフェイスを取得するのはそれほど複雑ではなく、Java を実装するのと同じように、対応する関数を順番に呼び出す必要があることがわかります。同様に、他の Java インターフェイスを呼び出したい場合も、実装原則は実際には同じです。

いくつかの関数を理解しましょう

1.クラスの検索

jclass MediaPlayer = Env->FindClass("android/media/MediaPlayer")

    jclass FindClass(const char* name) 
    { return function->FindClass(this, name); }

入力パラメータは検索対象のクラス名ですが、パッケージ名+クラス名の組み合わせが必要です。

 

2.メソッドIDの取得

 jmethodID gouzao = Env->GetMethodID(MediaPlayer, "<init>", "()V");

jmethodID setAudioStreamType = Env->GetMethodID(MediaPlayer, "setAudioStreamType", "(I)V");
jmethodID prepare = Env->GetMethodID(MediaPlayer, "prepare", "()V");

    jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) 
    { return 関数->GetMethodID(this, clazz, name, sig); }

最初のパラメータは 1 で取得したクラス名、2 番目のパラメータは取得するメソッド名、このメソッドはパラメータ 1 で実装する必要があり、型はパブリック型、パラメータ 3 はパラメータ 2 のパラメータ リスト型です。

最後のビットの意味を強調表示します。

lidonxiu0714 の紹介を参照してください。彼は非常によく説明しています。

Android Jni GetMethodID の関数識別の簡単な説明 - Lidongxiu0714's Blog - CSDN Blog

 

3.新しいオブジェクト

jobject jobj = Env->NewObject(MediaPlayer, gouzao);

    jobject NewObject(jclass clazz, jmethodID メソッドID, ...) 
    { 
        va_list args; 
        va_start(引数, メソッドID); 
        jobject result = 関数->NewObjectV(this、clazz、methodID、args); 
        va_end(args); 
        結果を返します。
    }

この関数は Java オブジェクトをインスタンス化するために使用されます。入力パラメータ 1 はクラス名、入力パラメータ 2 はコンストラクタID、次の入力パラメータは入力パラメータ 2 コンストラクタの関数入力パラメータです。これはコンストラクタ ID です。他の関数 ID の場合はエラーが報告されます。

 

4.CallVoidメソッド

Env->CallVoidMethod(jobj, setDataSource, path);

Env->CallVoidMethod(jobj, start);

 

    void CallVoidMethod(ジョブジェクトobj, jmethodIDメソッドID, ...) 
    { 
        va_list args; 
        va_start(引数, メソッドID); 
        関数->CallVoidMethodV(this、obj、methodID、args); 
        va_end(args); 
    }

このメソッドの最初のパラメータはインスタンス化後のクラス名、つまり上記3のジョブジェクト、入力パラメータ2はメソッドID、つまり上記2のjmethodID、それに続く入力パラメータは入力jmethodIDのパラメータリスト。

 

 

おすすめ

転載: blog.csdn.net/weixin_41028555/article/details/132413177