DXライブラリ Android版を使用した Androidアプリで Java のコードを実行する
( Android Studio編 )


 すべての処理を C++ で実行できれば良いのですが、Android の基本言語が Java である関係で、
Java を使用しないと使うことができない機能が沢山あります。

 なので、ここでは『DXライブラリ Android版』には無い『文字列を入力するダイアログを表示して、入力された
文字列を取得する』
という処理を行うための手順を通じて『DXライブラリ Android版』を使用するアプリで
Java のコードを実行するための方法を記します。


 1.『AndroidManifest.xml』の内容を Java のコードを実行できるように変更する

 2.Java のコードを入力する

 3.Java の情報を取得する C++ のコードを入力する



1.『AndroidManifest.xml』の内容を Java のコードを実行できるように変更する

  Android Studio『DXライブラリ Android版』を使用する Androidアプリのプロジェクトを開き
 画面左側のリストの『app』→『manifests』の中にある『AndroidManifest.xml』
 ダブルクリックして、内容を表示します。

  『AndroidManifest.xml』の内容は、使い方ページに沿って編集した場合は以下のようになっていると思いますが、
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.dxlibtest_androidstudio"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:hasCode="false"> <activity android:name="android.app.NativeActivity"> <meta-data android:name="android.app.lib_name" android:value="native-lib" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

  この中の以下のように変更します。(色が緑の部分が変更箇所や追加箇所で、2箇所です)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.dxlibtest_androidstudio"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:hasCode="true"> <activity android:name=".MainActivity"> <meta-data android:name="android.app.lib_name" android:value="native-lib" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
 


2.Java のコードを入力する

  Android Studio の画面左側のリストの『app』→『java』の中には使い方ページに沿ってプロジェクト名を
 『test』にした場合は『com.example.test』があり、更にその中に『MainActivity』がありますので、
 ダブルクリックして内容を表示すると最初から30行ほど書かれていますが、それを全部消して、代わりに
 今回の『文字列を入力するダイアログを表示して、入力された文字列を取得する』の処理を行うための
 以下のコードを入力します。
package com.example.(プロジェクト名); import android.app.NativeActivity; import android.os.Bundle; import android.widget.EditText; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.View; import java.lang.Runnable; public class MainActivity extends NativeActivity { NativeActivity AppActivity ; EditText EditView ; AlertDialog.Builder AlBuilder ; // 入力された文字列を保存するメンバー変数 String InputString ; // 文字列の入力が終わったら 1 にするフラグ用変数 int InputEnd ; // 文字列入力ダイアログを開始する public void StartInputStringDialog() { // NativeActivity の参照をメンバー変数に保存しておく AppActivity = this ; // 文字列の入力が終わったら 1 にするフラグを 0 で初期化 InputEnd = 0 ; // UIスレッドで実行する処理を登録する runOnUiThread( new Runnable () { // UIスレッドで呼ばれる関数 @Override public void run() { // 文字列入力の View を作成 EditView = new EditText( AppActivity ) ; // ダイアログを作成 AlBuilder = new AlertDialog.Builder( AppActivity ) ; // ダイアログのタイトルを設定 AlBuilder.setTitle( "テキスト入力ダイアログ" ) ; // ダイアログに文字列の View をセット AlBuilder.setView( EditView ) ; // ダイアログに OK ボタンを追加 AlBuilder.setPositiveButton( "OK", new DialogInterface.OnClickListener() { // OK ボタンが押されたときに呼ばれる関数 public void onClick( DialogInterface dialog, int whichButton ) { // 入力された文字列をメンバー変数に保存 InputString = EditView.getText().toString() ; // 入力されたかどうかのフラグを立てる InputEnd = 1 ; // タイトルバーとナビゲーションバーを非表示にする処理 View decor = AppActivity.getWindow().getDecorView() ; decor.setSystemUiVisibility( View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ); } }); // ダイアログを表示 AlBuilder.show() ; } }) ; } }
 ( (プロジェクト名)となっている箇所は、お手元のプロジェクトの名前を入力してください )



3.Java の情報を取得する C++ のコードを入力する

  次に Java の文字列入力を開始する関数を呼び出したり、入力された文字列を取得したりする C++ 側の
 プログラムです。
  『DXライブラリ Android版』でのみ使用できる GetNativeActivity という関数を使用しています。
#include "DxLib.h" #include <string.h> int android_main( void ) { JNIEnv *env ; const ANativeActivity *NativeActivity ; int InputEnd ; char InputString[ 1024 ] ; // 背景を灰色にする SetBackgroundColor( 128,128,128 ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; // アプリの NativeActivity を取得しておく NativeActivity = GetNativeActivity() ; // Java の関数 StartInputStringDialog の呼び出し { // JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 ) if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK ) { return -1 ; } // Java のクラス MainActivity を取得 jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ; // Java のクラス MainActivity のメンバー関数 StartInputStringDialog の ID を取得 jmethodID jmethodID_StartInputDialog = env->GetMethodID( jclass_MainActivity, "StartInputStringDialog", "()V" ) ; // Java のクラス MainActivity のメンバー関数 StartInputStringDialog の呼び出し env->CallVoidMethod( NativeActivity->clazz, jmethodID_StartInputDialog ) ; // Java のクラス MainActivity の参照を削除 env->DeleteLocalRef( jclass_MainActivity ) ; // JavaVM とソフト実行用スレッドの関連付け終了 NativeActivity->vm->DetachCurrentThread() ; } // 入力が完了したかどうかのフラグを倒す InputEnd = 0 ; // メインループ while( ProcessMessage() == 0 ) { // 裏画面の内容をクリア ClearDrawScreen() ; // 入力が完了していなかったら Java のクラス MainActivity のメンバー変数 InputEnd と InputString の情報を取得する if( InputEnd == 0 ) { // JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 ) if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK ) { return -1 ; } // Java のクラス MainActivity を取得 jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ; // Java のクラス MainActivity のメンバー変数 InputEnd の ID を取得 jfieldID jfieldID_InputEnd = env->GetFieldID( jclass_MainActivity, "InputEnd", "I" ) ; // Java のクラス MainActivity のメンバー変数 InputEnd の値をローカル変数 InputEnd に代入 InputEnd = env->GetIntField( NativeActivity->clazz, jfieldID_InputEnd ) ; // InputEnd が 1 になっていたら入力が完了しているので InputString の値を取得する if( InputEnd == 1 ) { // Java のクラス MainActivity のメンバー変数 InputString の ID を取得 jfieldID jfieldID_InputString = env->GetFieldID( jclass_MainActivity, "InputString", "Ljava/lang/String;" ) ; // Java のクラス MainActivity のメンバー変数 InputString の jstring オブジェクトを取得 jstring jstring_InputString = ( jstring )env->GetObjectField( NativeActivity->clazz, jfieldID_InputString ) ; // Java のクラス MainActivity のメンバー変数 InputString の jstring から C++ 用の文字列のアドレスを取得 const char *chars_InputString = env->GetStringUTFChars( jstring_InputString, NULL ) ; // 文字列をローカル変数 InputString にコピー strcpy( InputString, chars_InputString ) ; // Java のクラス MainActivity のメンバー変数 InputString の jstring から取得した C++ 用の文字列のアドレスを解放 env->ReleaseStringUTFChars( jstring_InputString, chars_InputString ) ; // Java のクラス MainActivity のメンバー変数 InputString の jstring オブジェクトの参照を削除 env->DeleteLocalRef( jstring_InputString ) ; } // Java のクラス MainActivity の参照を削除 env->DeleteLocalRef( jclass_MainActivity ) ; // JavaVM とソフト実行用スレッドの関連付け終了 NativeActivity->vm->DetachCurrentThread() ; } // InputEnd と InputString の状態を画面に描画 DrawFormatString( 0, 100, GetColor( 255,255,255 ), "InputEnd:%d InputString:%s", InputEnd, InputString ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End(); // ソフトの終了 return 0; }
 

  以上です。
  これでプロジェクトを実行すると、起動と同時に文字列入力ダイアログが現われ、文字列を入力して OK ボタンを押すと
 画面に入力した文字列が表示されると思います。

  詳細は割愛しますが、C++ から Java にアクセスする基本的な流れは。

   ① AttachCurrentThreadAsDaemon でソフト実行用スレッドと JavaVM を関連付け、JNIEnv も取得。

   ② GetObjectClass でアプリの Java クラスを取得。

   ③ GetMethodID や GetFieldID で Java の関数や変数の ID を取得。

   ④ Call???Method や Get???Field で Java の関数の呼び出しや変数の値を取得。

   ⑤ DeleteLocalRef で Get???Field で取得したオブジェクト系の変数の参照を削除。

   ⑥ DeleteLocalRef で GetObjectClass で取得したアプリの Java クラスの参照を削除。

   ⑦ DetachCurrentThread でソフト実行用スレッドと JavaVM の関連付けを終了。

  となります。
  C++ と Java でのやり取りを行う機能( JNI( Java Native Interface ) ) の詳しい扱い方については、検索サイトで
 『Android Java JNI』などのキーワードで検索して調べてみてください。





戻る