Android APK JNI sample (JAVA JNI)

原文来自:http://blog.youkuaiyun.com/eqiang8271/article/details/9967511

一个小实例介绍 Android JNI 如何实现步骤,其中有个遇到的加载库失败的教训:


1.  编写JAVA代码,写明要调用的本地动态链接库的本地方法:

  1. wnplib.java  
  2.   
  3. public class wnplib{  
  4.     public native void SayHello(String name);  
  5.   
  6.     static  
  7.     {  
  8.         System.loadLibrary("wnp");  
  9.     }  
  10.   
  11.     public static void main(String [] argv)  
  12.     {  
  13.         wnplib wp = new wnplib();  
  14.         wp.SayHello("myName");  
  15.     }  
  16. }  
wnplib.java

public class wnplib{
    public native void SayHello(String name);

    static
    {
        System.loadLibrary("wnp");
    }

    public static void main(String [] argv)
    {
        wnplib wp = new wnplib();
        wp.SayHello("myName");
    }
}

2. 编译javac 成.class文件

     

  1. javac wnplib.java  
javac wnplib.java


3.  使用javah 生成该类对应的C语言.h文件

     

  1. javah -classpath . wnplib  
javah -classpath . wnplib


4. 使用C/C++实现C的各函数


5. 在Android Source code 中编译代码生成.so库文件

     注意:此处需要注意,目前Android 有两种支持ARM 和 X86 两种,在不同的代码里编译的库有限制,是不是能弄个不依赖的? NDK编译我还没有实验。


    当编译ARM 和 X86 不一致的.so会出现如下的错误:

   

  1. 08-14 16:24:58.572 I/ActivityManager(  240): Start proc jni.wnptest.wnpjnitest for activity jni.wnptest.wnpjnitest/.WnptestActivity: pid=22268 uid=10000 gids={}  
  2. 08-14 16:24:58.592 E/jdwp    (22268): Failed sending reply to debugger: Broken pipe  
  3. 08-14 16:24:58.592 D/dalvikvm(22268): Debugger has detached; object registry had 1 entries  
  4. 08-14 16:24:58.602 D/WNP-TEST(22268): /vendor/lib:/system/lib:/system/lib/arm  
  5. 08-14 16:24:58.612 D/houdini (22268): [22268] Loading library(version: 2.0.7.42789 RELEASE)... successfully.  
  6. 08-14 16:24:58.612 D/houdini (22268): [22268] Open Native Library /system/lib/libwnp.so failed.  
  7. 08-14 16:24:58.612 W/dalvikvm(22268): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Ljni/wnptest/wnpjnitest/WnptestActivity;  
  8. 08-14 16:24:58.612 W/dalvikvm(22268): Class init failed in newInstance call (Ljni/wnptest/wnpjnitest/WnptestActivity;)  
  9. 08-14 16:24:58.612 D/AndroidRuntime(22268): Shutting down VM  
  10. 08-14 16:24:58.612 W/dalvikvm(22268): threadid=1: thread exiting with uncaught exception (group=0x4194e6f0)  
  11. 08-14 16:24:58.612 I/Process (22268): Sending signal. PID: 22268 SIG: 9  
  12. 08-14 16:24:58.612 E/AndroidRuntime(22268): FATAL EXCEPTION: main  
  13. 08-14 16:24:58.612 E/AndroidRuntime(22268): java.lang.ExceptionInInitializerError  
  14. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Class.newInstanceImpl(Native Method)  
  15. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Class.newInstance(Class.java:1319)  
  16. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.Instrumentation.newActivity(Instrumentation.java:1023)  
  17. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1872)  
  18. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1984)  
  19. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.access$600(ActivityThread.java:124)  
  20. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1148)  
  21. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.os.Handler.dispatchMessage(Handler.java:99)  
  22. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.os.Looper.loop(Looper.java:137)  
  23. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.main(ActivityThread.java:4436)  
  24. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.reflect.Method.invokeNative(Native Method)  
  25. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.reflect.Method.invoke(Method.java:511)  
  26. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)  
  27. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)  
  28. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at dalvik.system.NativeStart.main(Native Method)  
  29. 08-14 16:24:58.612 E/AndroidRuntime(22268): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: get_lib_extents[753]:   121 - /system/lib/libwnp.so is not a valid ELF object  
  30. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Runtime.loadLibrary(Runtime.java:370)  
  31. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.System.loadLibrary(System.java:535)  
  32. 08-14 16:24:58.612 E/AndroidRuntime(22268):     at jni.wnptest.wnpjnitest.WnptestActivity.<clinit>(WnptestActivity.java:39)  
  33. 08-14 16:24:58.612 E/AndroidRuntime(22268):     ... 15 more  
  34. 08-14 16:24:58.612 W/ActivityManager(  240):   Force finishing activity jni.wnptest.wnpjnitest/.WnptestActivity  
08-14 16:24:58.572 I/ActivityManager(  240): Start proc jni.wnptest.wnpjnitest for activity jni.wnptest.wnpjnitest/.WnptestActivity: pid=22268 uid=10000 gids={}
08-14 16:24:58.592 E/jdwp    (22268): Failed sending reply to debugger: Broken pipe
08-14 16:24:58.592 D/dalvikvm(22268): Debugger has detached; object registry had 1 entries
08-14 16:24:58.602 D/WNP-TEST(22268): /vendor/lib:/system/lib:/system/lib/arm
08-14 16:24:58.612 D/houdini (22268): [22268] Loading library(version: 2.0.7.42789 RELEASE)... successfully.
08-14 16:24:58.612 D/houdini (22268): [22268] Open Native Library /system/lib/libwnp.so failed.
08-14 16:24:58.612 W/dalvikvm(22268): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Ljni/wnptest/wnpjnitest/WnptestActivity;
08-14 16:24:58.612 W/dalvikvm(22268): Class init failed in newInstance call (Ljni/wnptest/wnpjnitest/WnptestActivity;)
08-14 16:24:58.612 D/AndroidRuntime(22268): Shutting down VM
08-14 16:24:58.612 W/dalvikvm(22268): threadid=1: thread exiting with uncaught exception (group=0x4194e6f0)
08-14 16:24:58.612 I/Process (22268): Sending signal. PID: 22268 SIG: 9
08-14 16:24:58.612 E/AndroidRuntime(22268): FATAL EXCEPTION: main
08-14 16:24:58.612 E/AndroidRuntime(22268): java.lang.ExceptionInInitializerError
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Class.newInstanceImpl(Native Method)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Class.newInstance(Class.java:1319)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.Instrumentation.newActivity(Instrumentation.java:1023)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1872)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1984)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.access$600(ActivityThread.java:124)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1148)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.os.Handler.dispatchMessage(Handler.java:99)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.os.Looper.loop(Looper.java:137)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at android.app.ActivityThread.main(ActivityThread.java:4436)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.reflect.Method.invokeNative(Native Method)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.reflect.Method.invoke(Method.java:511)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at dalvik.system.NativeStart.main(Native Method)
08-14 16:24:58.612 E/AndroidRuntime(22268): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: get_lib_extents[753]:   121 - /system/lib/libwnp.so is not a valid ELF object
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.Runtime.loadLibrary(Runtime.java:370)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at java.lang.System.loadLibrary(System.java:535)
08-14 16:24:58.612 E/AndroidRuntime(22268):     at jni.wnptest.wnpjnitest.WnptestActivity.<clinit>(WnptestActivity.java:39)
08-14 16:24:58.612 E/AndroidRuntime(22268):     ... 15 more
08-14 16:24:58.612 W/ActivityManager(  240):   Force finishing activity jni.wnptest.wnpjnitest/.WnptestActivity


6. Android APK 测试代码:

    注意:在加载库的时候需要 去掉库前缀字符串"lib", libwnp.so 加载的时候只需写wnp即可。

  1. package jni.wnptest.wnpjnitest;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.util.Log;  
  6.   
  7. public class WnptestActivity extends Activity {  
  8.       
  9.     /* 
  10.      * Create a game room. 
  11.      */  
  12.     public native int wnpCreateRoom(int port);  
  13.       
  14.       
  15.     static  
  16.     {     
  17.         Log.d("WNP-TEST", System.getProperty("java.library.path"));  
  18.         //System.out.println(System.getProperty("java.library.path"));   
  19.         try {  
  20.             System.loadLibrary("wnp");  
  21.         } catch (UnsatisfiedLinkError ule) {  
  22.             System.err.println("WARNING: Could not load library!");  
  23.         }  
  24.     }  
  25.       
  26.     /** Called when the activity is first created. */  
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.   
  32.     }  
  33.   
  34. }  
package jni.wnptest.wnpjnitest;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class WnptestActivity extends Activity {
    
    /*
     * Create a game room.
     */
    public native int wnpCreateRoom(int port);
    
    
    static
    {   
        Log.d("WNP-TEST", System.getProperty("java.library.path"));
        //System.out.println(System.getProperty("java.library.path")); 
        try {
            System.loadLibrary("wnp");
        } catch (UnsatisfiedLinkError ule) {
            System.err.println("WARNING: Could not load library!");
        }
    }
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

}


7. 注意Android APK 加载库需要在JNI中指定JAVA测试的类名及路径

  1.  *Java Application class path  
  2.  */  
  3. static const char *classPathName = "jni/wnptest/wnpjnitest/WnptestActivity";  
  4.   
  5. static JNINativeMethod methods[] = {  
  6.   
  7.   {"wnpSendDdata""([BI)I", (void*)JNICALL Java_WNP_wnpSendDdata },  
  8.   
  9.   {"wnpGetData""()[B", (void*)JNICALL Java_WNP_wnpGetData },  
  10.   
  11.   {"wnpCreateRoom""(I)I", (void*)JNICALL Java_WNP_wnpCreateRoom },  
  12.   
  13.   {"wnpJoinRoom""(Ljava/lang/String;I)I", (void*)JNICALL Java_WNP_wnpJoinRoom },  
  14.   
  15.   {"wnpQuitRoom""()I", (void*)JNICALL Java_WNP_wnpQuitRoom },  
  16.   
  17. };  
  18.   
  19.   
  20. /* 
  21.  * Register methods for one class. 
  22.  */  
  23. static int registerNativeMethods(JNIEnv* env, const char* className,  
  24.     JNINativeMethod* gMethods, int numMethods)  
  25. {  
  26.     jclass clazz;  
  27.   
  28.     clazz = (*env)->FindClass(env, className);  
  29.     if (clazz == NULL)  
  30.         return JNI_FALSE;  
  31.     if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)  
  32.     {  
  33.         printf("register nativers error");  
  34.         return JNI_FALSE;  
  35.     }  
  36.     return JNI_TRUE;  
  37. }  
  38.   
  39.   
  40. /*  
  41.  * Register methods for all classes.  
  42.  *  
  43.  * returns JNI_TRUE on success.  
  44.  */  
  45. static int registerNatives(JNIEnv* env)  
  46. {  
  47.   
  48.   if (!registerNativeMethods(env, classPathName,  
  49.                  methods, sizeof(methods) / sizeof(methods[0]))) {  
  50.     return JNI_FALSE;  
  51.   }  
  52.   return JNI_TRUE;  
  53.   
  54. }  
  55.   
  56. /*  
  57.  * Called by the VM when the shared library is loaded.  
  58.  */  
  59. jint JNI_OnLoad(JavaVM* vm, void* reserved)  
  60. {  
  61.     JNIEnv* env = NULL;  
  62.     jint result = -1;  
  63.   
  64.     WNP_LOGD("Entering JNI_OnLoad\n");  
  65.   
  66.     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)  
  67.         goto bail;  
  68.   
  69.     assert(env != NULL);  
  70.   
  71.     if (!registerNatives(env))  
  72.         goto bail;  
  73.   
  74.     /* success -- return valid version number */  
  75.     result = JNI_VERSION_1_6;  
  76.   
  77. bail:  
  78.     printf("Leaving JNI_OnLoad (result=0x%x)\n", result);  
  79.     return result;  
  80. }  
 *Java Application class path
 */
static const char *classPathName = "jni/wnptest/wnpjnitest/WnptestActivity";

static JNINativeMethod methods[] = {

  {"wnpSendDdata", "([BI)I", (void*)JNICALL Java_WNP_wnpSendDdata },

  {"wnpGetData", "()[B", (void*)JNICALL Java_WNP_wnpGetData },

  {"wnpCreateRoom", "(I)I", (void*)JNICALL Java_WNP_wnpCreateRoom },

  {"wnpJoinRoom", "(Ljava/lang/String;I)I", (void*)JNICALL Java_WNP_wnpJoinRoom },

  {"wnpQuitRoom", "()I", (void*)JNICALL Java_WNP_wnpQuitRoom },

};


/*
 * Register methods for one class.
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;

    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL)
        return JNI_FALSE;
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
    {
        printf("register nativers error");
        return JNI_FALSE;
    }
    return JNI_TRUE;
}


/* 
 * Register methods for all classes. 
 * 
 * returns JNI_TRUE on success. 
 */
static int registerNatives(JNIEnv* env)
{

  if (!registerNativeMethods(env, classPathName,
                 methods, sizeof(methods) / sizeof(methods[0]))) {
    return JNI_FALSE;
  }
  return JNI_TRUE;

}

/* 
 * Called by the VM when the shared library is loaded. 
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    WNP_LOGD("Entering JNI_OnLoad\n");

    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
        goto bail;

    assert(env != NULL);

    if (!registerNatives(env))
        goto bail;

    /* success -- return valid version number */
    result = JNI_VERSION_1_6;

bail:
    printf("Leaving JNI_OnLoad (result=0x%x)\n", result);
    return result;
}


8. 好的现在你可以测试实现的JNI了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值