この記事では、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 インターフェイスにアクセスするにはどうすればよいですか?
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のパラメータリスト。