プログラムの話。
ハマっている人がたぶん多数いると思うので、ここに残しておく。
開発環境はCocos2d-x-2.2.3、Windows、Androidアプリ開発。
Cocos2d-xのAndroid環境における、Greeが開発したCCWebviewは、
AndroidのJni関係の処理に不足があって、そのままだと
CCWebviewをcreateしたあとにメンバ変数でポインタを保持して別のところで
destroyとかsetVisibilityとかの処理をしようとすると、
EclipseのLogCatに、
JNI ERROR (app bug): accessed stale local reference 0x2d00025 (index 9 in a table of size 8)
というエラーを出してハングする。
これは、jobjectの参照するJavaのオブジェクトが、GC(ガベージコレクション)されると出るメッセージで、要するにもう有効でないアドレスにアクセスしているということ。
つまりメンバにとっといたと思っていたポインタが実はJavaによって破棄されていた、という状態。
Cでjobjectの値を保持していても、GCはそれが参照されていることを知らずに、開放してしまうというわけ。
じゃあどうすればいいのか?
結論から言うと、Gree提供のwebview_pluginのコードである、
Java_org_cocos2dx_lib_Cocos2dxWebView.cpp
に1行書き加えると直る。
以下の関数に1行加えればOK。
jobject createWebViewJni(){
JniMethodInfo t;
jobject ret = NULL;
if(JniHelper::getMethodInfo(t, “org/cocos2dx/lib/gree/webview/Cocos2dxWebView”, “<init>”, “()V”)){
ret = t.env->NewObject(t.classID, t.methodID);
t.env->DeleteLocalRef(t.classID);
ret = t.env->NewGlobalRef(ret); // これを追加
}
return ret;
}
NewGlobalRef(jobject)関数は、ローカル変数をグローバル変数にする関数で、
こうすることで勝手に解放されないように指示するわけだ。
この処理の追加によってハングは回避される。
あと、NewGlobalRef(jobject)でグローバル化した変数(のポインタ)は、
不要になったときに開放しないとメモリリークの原因になるので、
以下の関数に処理を入れること。
これも、
Java_org_cocos2dx_lib_Cocos2dxWebView.cpp
内にある関数。
void destroyJni(jobject obj){
JniMethodInfo t;
if(getInstanceMethodInfo(t, obj, “destroy”, “()V”)){
t.env->CallVoidMethod(obj, t.methodID);
t.env->DeleteLocalRef(t.classID);
t.env->DeleteGlobalRef(obj); // これを追加
}
}
以下参考サイト。
一部機能だけをcocos2d-xにするには? – technica
http://technica.speee.jp/601
JNIでNewGlobalRef, DeleteGlobalRefを使う | TechRacho
http://techracho.bpsinc.jp/baba/2013_03_08/6587
JNI ERROR (app bug): accessed stale local reference | Cocos2d-x
http://www.cocos2d-x.org/forums/6/topics/50008
ほか100ページ以上参照して調べたけどこの3サイトが特に役立った。
ありがとうございます。
今回なにが苦労したかというと、Cocos2d-xの情報サイトがそんなにないのと、
CCWebviewは使ってる人が少ないのかさらに情報がない&本家も説明がほぼないこと、
Cocos2d-xがJavaとC++をまたぐ際にJniとかいうクッション技術を使っていること、
などなどが絡み合って理解しながら解決法を探したので6時間以上パソコンと
向かい合ってたよ。頼むよマジで。
この前にiPhoneで作ったアプリをAndroidに移行しようとしたら、
さまざまなソフトをバージョンを気にしながらインストールしたり、
開発環境のeclipseが正しいソースファイルなのにエラーがあると言い出したり、
makeファイルの記述から覚えないといけなかったり、
そもそもブレークポイントのデバグができなかったりで、
環境構築&ビルド成功までに2日かかった。
iPhoneの開発はペロッとなにも引っかからずにすぐできたけど
Androidの開発環境引っかかるところ多すぎっしょ。
ほんとこれ精神やられるくらい難度高いよ(笑)。
accessed stale local referenceのエラーは、
ボスのあとにラスボス出現かよ!みたいな状態だったよ。
まあでも終わってよかった。
あとは調整で終わりだ。
ニュースレター登録お願いします