zoukankan      html  css  js  c++  java
  • Android项目中JNI技术生成并调用.so动态库实现详解

        生成 jni方式有两种:一种是通过SWIG从C++代码生成过度的java代码;另一种是通过javah的方式从java代码自动生成过度的C++代码。两种方式下的步骤流程正好相反。

    第一种方式:由于需要配置SWIG环境,有点麻烦了,所以往往大家不采用这个途径,参照博文http://my.oschina.net/liusicong/blog/314162

    第二种方式:javah的方式则通过shell指令就可以完成整个流程,该过程大概包括以下步骤:

    1. 编写 Java 代码。我们将从编写 Java 类开始,这些类执行三个任务:声明将要调用的本机方法;装入包含本机代码的共享库;然后调用该本机方法。
    2. 编译 Java 代码。在使用 Java 类之前,必须成功地将它们编译成字节码。

    3. 创建 C/C++ 头文件。C/C++     头文件将声明想要调用的本机函数说明。然后,这个头文件与 C/C++ 函数实现(请参阅步骤 4)一起来创建共享库(请参阅步骤 5)。

    4. 编写 C/C++ 代码。这一步实现 C 或     C++ 源代码文件中的函数。C/C++ 源文件必须包含步骤 3 中创建的头文件。

    5. 创建共享库文件。从步骤 4 中创建的 C 源代码文件来创建共享库文件。

    6. 运行 Java 程序。运行该代码,并查看它是否有用。我们还将讨论一些用于解决常见错误的技巧。

    第二种方法的具体实现方式和例子如下:

    1. 在Eclipse中创建项目:TestJNI

    2. 新创建一个class:TestJNI.java

    package com.wwj.jni;
     public class TestJNI {    
        public native boolean Init();    
        public native int Add(int x, int y);    
        public native void Destory();
    }

    以上代码声明三个本地方法。

    3. 编译JNI

    找到Android项目中bin目录下,会有classes文件夹,Eclipse自动为我们生成的字节码文件就在这个目录下。

    我们在该路径下,使用javah命令,生成我们想要得到的.h头文件,如下图所示:

    执行javah -jni com.wwj.jni.TestJNI命令之后,会在classes目录下生成头文件:com_wwj_jni_TestJNI.h

    将它复制到jni文件夹下,打开如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */
     #include <jni.h>
    /* Header for class com_wwj_jni_TestJNI */
     #ifndef _Included_com_wwj_jni_TestJNI
     #define _Included_com_wwj_jni_TestJNI
     #ifdef __cplusplusextern "C" {
    #endif
    /*
     * Class:     com_wwj_jni_TestJNI
     * Method:    Init
     * Signature: ()Z
     */
     JNIEXPORT jboolean JNICALL Java_com_wwj_jni_TestJNI_Init
      (JNIEnv *, jobject);
    /*
     * Class:     com_wwj_jni_TestJNI
     * Method:    Add
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_wwj_jni_TestJNI_Add
      (JNIEnv *, jobject, jint, jint);
    /*
     * Class:     com_wwj_jni_TestJNI
     * Method:    Destory
     * Signature: ()V 
     */
     JNIEXPORT void JNICALL Java_com_wwj_jni_TestJNI_Destory
      (JNIEnv *, jobject);
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    以上代码就是通过javah命令生成jni层代码。

    4. 使用C/C++实现JNI

    在jni文件夹下,创建com_wwj_jni_TestJNI.h对应的cpp文件:com_wwj_jni_TestJNI.cpp

    我们再添加两个文件Add.h,Add.cpp,具体实现放在这两个文件中来完成。

    Add.h

    #ifndef _TEST_JNI_ADD_H_
     #define _TEST_JNI_ADD_H_
        class CAdd {public:
             CAdd();    
            ~CAdd();    
            int Add(int x, int y);
        };
    #endif

    Add.cpp

    #include "Add.h"
     CAdd::CAdd() {
     }
     CAdd::~CAdd() {
     }
     int CAdd::Add(int x, int y) {    
     return x + y;
    }

    com_wwj_jni_TestJNI.cpp的实现:

    #include <stdio.h>
    #include <stdlib.h>
    #include "com_wwj_jni_TestJNI.h"
    #include "Add.h"
    Add *pCAdd = NULL;
    JNIEXPORT jboolean JNICALL Java_com_wwj_jni_TestJNI_Init(JNIEnv *env,jobject obj) {   
       if (pCAdd == NULL) {
            pCAdd = new CAdd;
        }    
       return pCAdd != NULL;
    }
    JNIEXPORT jint JNICALL Java_com_wwj_jni_TestJNI_Add(JNIEnv *env, jobject obj,
            jint x, jint y) {    
            int res = -1;    
           if (pCAdd != NULL) {
              res = pCAdd->Add(x, y);
            }    
           return res;
    }
    JNIEXPORT void JNICALL Java_com_wwj_jni_TestJNI_Destory(JNIEnv *env, jobject obj)
    {    if (pCAdd != NULL)
        {
            pCAdd = NULL;
        }
    }

    5. 创建mk文件,并使用ndk-build命令生成.so动态链接库文件

    在jni目录下创建Android.mk文件如下:

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := TestJNI
    LOCAL_SRC_FILES := com_wwj_jni_TestJNI.cpp
    LOCAL_SRC_FILES += Add.cpp
    include $(BUILD_SHARED_LIBRARY)

    其中:

    LOCAL_PATH是C/C++代码所在目录,也就是我们的jni目录。

    LOCAL_MODULE是要编译的库的名称。编译器会自动在前面加上lib,在后面加上.so。

    LOCAL_SRC_FILES是要编译的C/C++文件。

    然后我还需要在Android项目根目录下创建Application.mk文件:

    APP_PROJECT_PATH := $(call my-dir)
    APP_MODULES := TestJNI

    写完了这两个mk文件,我们就可以用ndk来为我们生成相应的动态链接库了。前提你需要下载NDK,并把NDK路径配置到path环境变量中去,笔者配置的路径是:D:Cocos2dxandroid-ndk-r9d,具体视个人情况而定。

    进入Application.mk文件所在目录,在命令行中使用ndk-build生成.so文件

    编译成功后会在工程目录的libs/armeabi目录下生成一个libTestJNI.so文件。

    项目结构会变成如下:

    6. 在Java中调用JNI

    package com.wwj.jni;
    import android.os.Bundle;
    import android.widget.TextView;
    import android.app.Activity;
    public class TestJNIActivity extends Activity {    
    private TextView textView;    
    static {        // 加载动态库
            System.loadLibrary("TestJNI");
        }
        @Override    
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView = (TextView) findViewById(R.id.textview);
            TestJNI testJNI = new TestJNI();        // 调用native方法
            boolean init = testJNI.Init();        
           if (init == true) {            // 调用Add函数
                int sum = testJNI.Add(100, 150);
                textView.setText("你真是个" + sum);
            } else {
                textView.setText("你比二百五还要二百五");
            }
            testJNI.Destory();
        }
    }

    运行项目,效果图如下:

    按照以上步骤完全可以生成一个属于自己的.so文件,且可正确调用和执行,这里补充一下两点:

    注意一:NDK的环境配置:

    1,下载地址:

    Android NDK r10e:

        32位:http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86.exe

        64位:http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe

    Android NDK r9d:

        32位:https://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip

        64位: https://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip

    自己用的是ndk-r9d版本,以上地址需要FQ,需要的对应版本留下邮箱就好。

    2,配置PATH环境变量,cmd命令行输入ndk-build,出现一下内容提示表示配置正确。

    Android NDK: Could not find application project directory !
    Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
    D:javaandroid-ndk-r9duild/core/build-local.mk:148: *** Android NDK: Aborting
        .  Stop.

    注意二:参考以上文章在最后输入ndk-build时会提示以下错误:

    此时修改一下Application.mk文件里的:

    APP_PROJECT_PATH := $(call my-dir)/ 成 APP_PROJECT_PATH := $(call my-dir)/..

    文章转载于:http://www.cnblogs.com/sevenyuan/p/4202759.html

  • 相关阅读:
    Ftp、Ftps与Sftp之间的区别
    Previous Workflow Versions in Nintex Workflow
    Span<T>
    .NET Core 2.0及.NET Standard 2.0 Description
    Announcing Windows Template Studio in UWP
    安装.Net Standard 2.0, Impressive
    SQL 给视图赋权限
    Visual Studio for Mac中的ASP.NET Core
    How the Microsoft Bot Framework Changed Where My Friends and I Eat: Part 1
    用于Azure功能的Visual Studio 2017工具
  • 原文地址:https://www.cnblogs.com/snow-flower/p/6086163.html
Copyright © 2011-2022 走看看