• 【转】Android下编译jni库的二种方法(含示例)


    原文网址:http://blog.sina.com.cn/s/blog_3e3fcadd01011384.html

    总结如下:两种方法是:
    1)使用Android源码中的Make系统
    2)使用NDK(从NDK r5开始)

    ---------------------------------
    源码要求: 如果Android工程的顶层目录为my_android_project_name:
    1) my_android_project_name/jni/Android.mk文件的示例内容如下(以生成libjni_mouse.so的C代码为例):
      LOCAL_PATH:= $(call my-dir)
      include $(CLEAR_VARS)
      LOCAL_PRELINK_MODULE := false
      LOCAL_MODULE := libjni_mouse
      LOCAL_SRC_FILES := jni_mouse.c
      LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
      LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib  -llog
      LOCAL_SHARED_LIBRARIES := libcutils
      include $(BUILD_SHARED_LIBRARY)

    2)源文件的部分内容(仅供参考):
      #include <stdio.h>
      #include <unistd.h>
      #include <errno.h>
      #include <linux/input.h>
      #include <linux/uinput.h>

      #include <jni.h>                    // located in $JDK/include
      #include <cutils/log.h>         // for Android Make system: $Android_SRC/system/core/include/cutils/log.h
      //#include <android/log.h>   // for NDK compiler

      #define LOG_DBG(tag,fmt,args...)  __android_log_print(ANDROID_LOG_DEBUG,tag,fmt,##args)
      #define LOG_ERR(tag,fmt,args...)  __android_log_print(ANDROID_LOG_ERROR,tag,fmt,##args)
      #ifdef ___DEBUG
        #define DBG(fmt, args...)  __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
      #else
        #define DBG(fmt, args...)
      #endif //___DEBUG
      #define OUT(fmt, args...)    __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

      #define JNIREG_CLASS            "com/my_organization/my_pkg/JniMouse"

      static JNINativeMethod JniMouseMethods[] = {
         { "nativeOpenMouse",            "()I",                   (void*) openMouse },
         { "nativeCloseMouse",           "()V",                   (void*) closeMouse },
         { "nativeMoveCursor",           "(II)V",                 (void*) moveCursor },
         ...
      };

      static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* methods,
                                                           int   numMethods)
      {   
        jclass clazz;
       
        // C++ way:  clazz= env->FindClass(className);
        clazz = (*env)->FindClass(env, className);
        if (clazz == NULL) {
            LOG_ERR(TAG, "Native registration error: unable to find class ");
            return JNI_FALSE;
        }
        // C++ way:  if (env->RegisterNatives(clazz, methods, numMethods) < 0)
        if ((*env)->RegisterNatives(env, clazz, methods, numMethods) < 0) {
            LOG_ERR(TAG, "RegisterNatives failed ");
            return JNI_FALSE;
        }

        return JNI_TRUE;
      }

      static int registerNatives(JNIEnv* env)
      {
        if (!registerNativeMethods(env, JNIREG_CLASS, JniMouseMethods,
                     sizeof(JniMouseMethods) / sizeof(JniMouseMethods[0])))
            return JNI_FALSE;
        return JNI_TRUE;
      }

      jint JNI_OnLoad(JavaVM* vm, void* reserved)
      {
       JNIEnv* env = NULL;
       jint result = -1;
      
        // this is for C++: if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
        if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
            LOG_ERR(TAG, "ERROR: GetEnv failed ");
            goto bail;
        }
        assert(env != NULL);
           
        if (!registerNatives(env)) {
            LOG_ERR(TAG, "ERROR: jni_mouse native registration failed ");
            goto bail;
        }
       
        result = JNI_VERSION_1_4;

      bail:
        return result;
      }


    ---------------------------------
    编译过程具体如下:
    1)使用Android源码中的Make系统:
    $  cd   $ANDROID_SRC    # (e.g. /u_data/android/sourcecode/and22)
    $  .      build/envsetup.sh
    # 这样就会生成许多shell工具,实际上是shell函数。

    $  lunch  MY_LUNCH_NUMBER    # 如果你的项目需要用到PLATFORM相关的内容(共享库/java库等)

    # 把Android工程的顶层目录符号链接(或者拷贝)到 $ANDROID_SRC/packages/apps,如
    $  ln  -fs  /abs/path/to/my_android_project_name  $ANDROID_SRC/packages/apps

    $  mmm  packages/apps/my_android_project_name
    # 如果没有错误,就会生成以下文件(取决于你使用的PRODUCT名字):
    #       $ANDROID_SRC/out/target/product/$PRODUCT_NAME/system/lib/libjni_mouse.so

    # 最后拷贝生成的库文件到Android工程的libs/armeabi/目录下:
    $  mkdir -p $ANDROID_SRC/packages/apps/my_android_project_name/libs/armeabi
    $  cp  $ANDROID_SRC/out/target/product/$PRODUCT_NAME/system/lib/libjni_mouse.so    
              $ANDROID_SRC/packages/apps/my_android_project_name/libs/armeabi

    #  这样,在eclipse中正常编译/生成.apk文件时,就会把生成的jni库自动包含进.apk文件中,这可以使用unzip命令来验证:
    #      cp my.apk /tmp/tmp/my.zip; cd /tmp/tmp; unzip my.zip; ls -l  lib/armeabi/lib*.*

    2)使用NDK(from NDK r5)
    从NDK r5开始,NDK正式作为独立的工具来编译jni的代码,但它往往缺少某些头文件,如<linux/uinput.h>。
    0)准备环境变量,如:
       $ export  NDK=/u_data/android/sourcecode/android-ndk-r6b
       $ export        CC=$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc
       $ export  STRIP=$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-strip
       $ export  SYSROOT=$NDK/platforms/android-8/arch-arm   # 要看你使用的目标Android的版本 :)

    1) 对于缺少的头文件,可以借用PC上的x86下的同名文件,如:
        cd   $NDK/platforms/android-8/arch-arm/usr/include/linux
        ln   -fs   ../../../../arch-x86/usr/include/linux/uinput.h   .

    2) 编译出可执行文件(如果有main函数),如:
       $   $CC --sysroot=$SYSROOT   -o  my_jni_mouse_exe    jni_mouse.c   my_main_func.c
       #注: '--sysroot=dir':Use dir as the logical root directory for headers and libraries.

    3) 编译出共享库(如果没有main函数),如:
       $   $CC --sysroot=$SYSROOT -fPIC     -o     jni_mouse.o     -c  jni_mouse.c        # optional '-o ...'
       $   $CC --sysroot=$SYSROOT -shared -o libjni_mouse.so        jni_mouse.o
       # 再strip一下,以便减少其大小(直接覆盖原来的库文件):
       $   $STRIP    libjni_mouse.so

    4)(可选)链接如上刚生成的共享库:
       $   $CC --sysroot=$SYSROOT -L. -ljni_mouse  -o  my_hello  my_hello.c

    <EOF>

  • 相关阅读:
    Docker常见应用部署(3)
    数据库 'FileServer' 的版本为 904,无法打开。此服务器支持 852 版及更低版本。不支持降级路径。 无法打开新数据库
    Dockerfile 构建镜像(4)
    DockerHub 镜像仓库(5)
    ASP.NET Core 6.0 中使用 Autofac
    ASP.NET Core 6.0 使用RabbitMQ
    安装node.js环境,构建第一个vue项目
    Chrome 搜索结果始终保持新标签打开
    最短路
    [转载] Open3D显示点云常见方式
  • 原文地址:https://www.cnblogs.com/wi100sh/p/4616182.html
Copyright © 2020-2023  润新知