free pascal(lazarus)版的android JNI進階篇:反向呼叫java的方法並傳遞複雜引數
這篇文章雖然短暫,但耗用了筆者一天的時間搜尋各種資料,除錯了無數次,在這裡跟大家分享是想大家碰到類似問題時少走彎路,請各位轉載註明出處,http://blog.csdn.net/rocklee 。
查閱了無數C、C++、pascal、java呼叫JNI的例子,CallxxxMethod的無引數、單一引數的例子很多,但是如果呼叫多個引數,傳遞的引數型別複雜的幾乎沒有,後來沒辦法,再回頭看看java的反射執行機制的程式碼,翻出幾個月前自己用java寫的類加密執行時的測試程式碼。本文java版的實現請看 點選開啟連結
再對比native呼叫java jni的方法,得到一個結論就是,它們的流程是高度一致的,我能用java實現,應該也可以用native實現,但是有區別,比如通用的native中的GetMethodID就不能穿Class[]型別的引數進去,因為各種native語言對Class的處理時資料儲存方法不一樣(跟java跟是不著調了)
There are several functions in the JNI that require, as a parameter, the signature of another function. The type of this parameter is a string. The table below shows how Java types are mapped into characters (e.g. boolean is mapped as the uppercase letter
Java Type | Signature |
boolean | Z |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
void | V |
object | Lfully-qualified-class |
type[] | [type |
method signature | ( arg-types) ret-type |
Examples:
Method | Signature |
void f1() | ()V |
int f2(int, long) | (IJ)I |
boolean f3(int[]) | ([I)B |
double f4(String, int) | (Ljava/lang/String;I)D |
void f5(int, String [], char) | (I[Ljava/lang/String;C)V |
看明白了沒有?我再舉個例子,如果我要找尋上文中Test的public String multiParametersTest(byte[] bytes,int i,int j,String s)這個方法,那麼應該這樣寫:
method := Env^^.GetMethodID(env, cls, 'multiParametersTest', '([BIILjava/lang/String;)Ljava/lang/String;');
好了,method找到,那麼如何執行這個multiParametersTest呢? 因為網上資料沒有,我一直在用CallObjectMethodA和CallObjectMethodV去嘗試,也為了PJValue這個引數型別和va_list這個引數型別作了很多遍嘗試,對於va_list這個引數型別,連官網都沒任何解釋更不用說example了。
好了,此文只起到拋磚引玉的作用,希望有興趣用pascal寫android NDK的朋友關注一下 http://www.pacifier.com/~mmead/jni/delphi/JEDI/DOCS/delphi-jni-2.html 這個網站,上面的資料雖然不是針對android,但是跟android的jni是高度一致的。上年oracle要狀告谷歌用了java語法侵權索賠幾個億不是無中生有的。
題外話,為了查閱程式碼,翻了很多android影象類程式碼,發現很多方法是呼叫自帶native實現的,java的程式碼只是起到黏合作用而已,也就是說本來效率就很不錯。