#include "DxLib.h"
#include <string.h>
// データ取得用バッファ 8MB( 足りない場合は増やしてください )
BYTE HTTP_DataBuffer[ 8 * 1024 * 1024 ] ;
// HTTP通信を行う
// URL : 接続するパス
// Method : "GET", "POST", "PUT" の何れか
// 戻り値 : 0:成功 -1:エラー
int Android_HTTP_Connect( const char *URL, const char *Method )
{
JNIEnv *env ;
const ANativeActivity *NativeActivity ;
jstring jstring_URL ;
int MethodType = 0 ;
// アプリの NativeActivity を取得しておく
NativeActivity = GetNativeActivity() ;
// JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 )
if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK )
{
return -1 ;
}
// URL から jstring を作成
jstring_URL = env->NewStringUTF( URL ) ;
// メソッド名からメソッドタイプの数値をセット
if( strcmpDx( "GET", Method ) == 0 )
{
MethodType = 0 ;
}
else
if( strcmpDx( "POST", Method ) == 0 )
{
MethodType = 1 ;
}
else
if( strcmpDx( "PUT", Method ) == 0 )
{
MethodType = 2 ;
}
// Java のクラス MainActivity を取得
jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ;
// Java のクラス MainActivity のメンバー関数 HTTP_Connect の ID を取得
jmethodID jmethodID_HTTP_Connect = env->GetMethodID( jclass_MainActivity, "HTTP_Connect", "(Ljava/lang/String;I)V" ) ;
// Java のクラス MainActivity のメンバー関数 HTTP_Connect の呼び出し
env->CallVoidMethod( NativeActivity->clazz, jmethodID_HTTP_Connect, jstring_URL, MethodType ) ;
// Java の参照を削除
env->DeleteLocalRef( jclass_MainActivity ) ;
env->DeleteLocalRef( jstring_URL ) ;
// JavaVM とソフト実行用スレッドの関連付け終了
NativeActivity->vm->DetachCurrentThread() ;
// 正常終了
return 0 ;
}
// HTTP通信の結果を取得する
// 戻り値 : 通信の結果( 0:まだ通信中 1以上:HTTPレスポンスコード -2:IO例外発生 -3:MalformedURL例外発生 )
int Android_HTTP_GetResponseCode( void )
{
JNIEnv *env ;
const ANativeActivity *NativeActivity ;
int Result = -1 ;
// アプリの NativeActivity を取得しておく
NativeActivity = GetNativeActivity() ;
// JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 )
if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK )
{
return -1 ;
}
// Java のクラス MainActivity を取得
jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ;
// Java のクラス MainActivity のメンバー変数の ID を取得
jfieldID jfieldID_HTTP_ResponseCode = env->GetStaticFieldID( jclass_MainActivity, "HTTP_ResponseCode", "I" ) ;
jfieldID jfieldID_HTTP_Connect_Finish = env->GetStaticFieldID( jclass_MainActivity, "HTTP_Connect_Finish", "I" ) ;
// Java のクラス MainActivity のメンバー変数の値を取得
jint jint_HTTP_ResponseCode = env->GetStaticIntField( jclass_MainActivity, jfieldID_HTTP_ResponseCode ) ;
jint jint_HTTP_Connect_Finish = env->GetStaticIntField( jclass_MainActivity, jfieldID_HTTP_Connect_Finish ) ;
// まだ通信処理が終わっていなかったら 0 を返す
if( jint_HTTP_Connect_Finish == 0 )
{
Result = 0 ;
}
else
{
// 終わっていたらレスポンスコードを返す
Result = jint_HTTP_ResponseCode ;
}
// JavaVM とソフト実行用スレッドの関連付け終了
NativeActivity->vm->DetachCurrentThread() ;
// 戻り値を返す
return Result ;
}
// HTTP通信の例外メッセージを所得する
// 戻り値 : 例外のメッセージ文字列のポインタ
char *Android_HTTP_GetExceptionMessage( void )
{
JNIEnv *env ;
const ANativeActivity *NativeActivity ;
static char HTTP_ExceptionMessage[ 64 * 1024 ] ;
// アプリの NativeActivity を取得しておく
NativeActivity = GetNativeActivity() ;
// JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 )
if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK )
{
return NULL ;
}
// Java のクラス MainActivity を取得
jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ;
// Java のクラス MainActivity のメンバー変数の ID を取得
jfieldID jfieldID_HTTP_ExceptionMessage = env->GetStaticFieldID( jclass_MainActivity, "HTTP_ExceptionMessage", "Ljava/lang/String;" ) ;
// Java のクラス MainActivity のメンバー変数の値を取得
jstring jstring_HTTP_ExceptionMessage = ( jstring )env->GetStaticObjectField( jclass_MainActivity, jfieldID_HTTP_ExceptionMessage ) ;
// jstring の文字列をグローバル変数にコピー
const char *utf8_HTTP_ExceptionMessage = env->GetStringUTFChars( jstring_HTTP_ExceptionMessage, NULL ) ;
if( utf8_HTTP_ExceptionMessage != NULL )
{
strcpyDx( HTTP_ExceptionMessage, utf8_HTTP_ExceptionMessage ) ;
}
else
{
HTTP_ExceptionMessage[ 0 ] = '\0' ;
}
env->ReleaseStringUTFChars( jstring_HTTP_ExceptionMessage, utf8_HTTP_ExceptionMessage ) ;
// JavaVM とソフト実行用スレッドの関連付け終了
NativeActivity->vm->DetachCurrentThread() ;
// メッセージ文字列を返す
return HTTP_ExceptionMessage ;
}
// HTTP通信の結果得られたデータのバッファを取得する
// BufferBytes : バッファに格納されているデータのサイズを保存する変数のアドレス
// 戻り値 : データのバッファの先頭アドレス
void *Android_HTTP_GetBuffer( size_t *BufferBytes )
{
JNIEnv *env ;
const ANativeActivity *NativeActivity ;
void *Result = NULL ;
// アプリの NativeActivity を取得しておく
NativeActivity = GetNativeActivity() ;
// JavaVM とソフト実行用スレッドを関連付け( C++ から Java の機能を使用するために必要 )
if( NativeActivity->vm->AttachCurrentThreadAsDaemon( &env, NULL ) != JNI_OK )
{
return NULL ;
}
// Java のクラス MainActivity を取得
jclass jclass_MainActivity = env->GetObjectClass( NativeActivity->clazz ) ;
// Java のクラス MainActivity のメンバー変数の ID を取得
jfieldID jfieldID_HTTP_DataBuffer = env->GetStaticFieldID( jclass_MainActivity, "HTTP_DataBuffer", "[B" ) ;
jfieldID jfieldID_HTTP_DataBufferEnableBytes = env->GetStaticFieldID( jclass_MainActivity, "HTTP_DataBufferEnableBytes", "I" ) ;
// Java のクラス MainActivity のメンバー変数の内容を取得
jint jint_HTTP_DataBufferEnableBytes = env->GetStaticIntField( jclass_MainActivity, jfieldID_HTTP_DataBufferEnableBytes ) ;
// 有効なデータが 1byte でもあれば、バッファの内容を取得する
if( jint_HTTP_DataBufferEnableBytes > 0 )
{
// Java のクラス MainActivity のメンバー変数 HTTP_DataBuffer の内容を取得
jbyteArray jbyteArray_HTTP_DataBuffer = ( jbyteArray )env->GetStaticObjectField( jclass_MainActivity, jfieldID_HTTP_DataBuffer ) ;
jbyte *jbyte_Elements = env->GetByteArrayElements( jbyteArray_HTTP_DataBuffer, NULL ) ;
memcpy( HTTP_DataBuffer, jbyte_Elements, jint_HTTP_DataBufferEnableBytes ) ;
env->ReleaseByteArrayElements( jbyteArray_HTTP_DataBuffer, jbyte_Elements, 0 ) ;
env->DeleteLocalRef( jbyteArray_HTTP_DataBuffer ) ;
Result = HTTP_DataBuffer ;
}
// バッファの有効なデータのサイズを保存
*BufferBytes = jint_HTTP_DataBufferEnableBytes ;
// JavaVM とソフト実行用スレッドの関連付け終了
NativeActivity->vm->DetachCurrentThread() ;
// バッファのアドレスを返す
return Result ;
}
int android_main( void )
{
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
// HTTP通信開始
Android_HTTP_Connect( "https://dxlib.xsrv.jp/index.html", "GET" ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen() ;
// HTTP通信の結果によって処理を分岐
int ResponseCode = Android_HTTP_GetResponseCode() ;
switch( ResponseCode )
{
case 0 :
// 通信が終了していない場合は『通信中』を表示する
DrawString( 0, 0, "通信中", GetColor( 255,255,255 ) ) ;
break ;
case -2 :
// IO例外が発生した場合はメッセージを表示する
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "IO例外発生 : %s", Android_HTTP_GetExceptionMessage() ) ;
break ;
case -3 :
// MalformedURL例外が発生した場合はメッセージを表示する
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "MalformedURL例外発生 : %s", Android_HTTP_GetExceptionMessage() ) ;
break ;
default :
// それ以外の場合は HTTPレスポンスコード
// データのサイズとアドレスを取得
size_t DataBytes ;
void *Buffer = Android_HTTP_GetBuffer( &DataBytes ) ;
DrawFormatString( 0, 16 * 0, GetColor( 255,255,255 ), "HTTPレスポンスコード : %d", ResponseCode ) ;
DrawFormatString( 0, 16 * 1, GetColor( 255,255,255 ), "データのサイズ : %d bytes", ( int )DataBytes ) ;
DrawFormatString( 0, 16 * 2, GetColor( 255,255,255 ), "データ : %s", Buffer != NULL ? ( char * )Buffer : "None" ) ;
break ;
}
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
以上です。
これでプロジェクトを実行すると、『DXライブラリ置き場』のトップページを HTTP通信でダウンロードする処理が実行され、
画面に HTML のテキストが表示されます。( 通信が成功すれば、ですが… )
詳細は割愛しますが、C++ から Java にアクセスする基本的な流れは。
① AttachCurrentThreadAsDaemon でソフト実行用スレッドと JavaVM を関連付け、JNIEnv も取得。
② GetObjectClass でアプリの Java クラスを取得。
③ GetMethodID や GetFieldID で Java の関数や変数の ID を取得。( static な変数の場合は GetStaticFieldID )
④ Call???Method や Get???Field で Java の関数の呼び出しや変数の値を取得。
⑤ DeleteLocalRef で Get???Field で取得したオブジェクト系の変数の参照を削除。
⑥ DeleteLocalRef で GetObjectClass で取得したアプリの Java クラスの参照を削除。
⑦ DetachCurrentThread でソフト実行用スレッドと JavaVM の関連付けを終了。
となります。
C++ と Java でのやり取りを行う機能( JNI( Java Native Interface ) ) の詳しい扱い方については、検索サイトで
『Android Java JNI』などのキーワードで検索して調べてみてください。
戻る