zoukankan      html  css  js  c++  java
  • Android NDK 使用第一步,编译c文件,声明jni并调用。

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://eshock.blogbus.com/logs/61459223.html

    在google docs中阅读

    Android NDK学习笔记

    前言

    Android系统中的应用程序都是用Java开发的。Android NDK使我们能够在android上使用C/C++开发的原生代码。有两个理由使用NDK: 一是合理的重用现有的代码;二是在程序中某些关键的部分提高执行效率。
    这里先讲几个符号的约定:
    <project> - 你的Android应用程序工程的目录
    <ndk> - 你的ndk安装的目录

    捷径

    这里先扯一句题外话 -- 如果你不需要使用NDK开发,只是需要使用第三方用NDK开发的库,那么你只需要这样做:
    把第三方提供的libxxx.so放到你的<project>/libs/armeabi/下, 然后在程序随便什么地方中加入
    static {
        System.loadLibray("xxx");
    }
    就可以使用该库了。

    安装NDK

    NDK的安装很简单:
    1. 首先要将SDK升级至最新,然后下载ndk(可能要FQ,恩恩)将它解压到某个目录<ndk>下。
    2. 运行: <ndk>/build/host-setup.sh
    3. 如果成功的话就OK了,如果失败的话检查一下你是不是下载了正确的ndk版本(例如你的操作系统是linux而下载了windows版的ndk).

    Java部分

    现在我们用一个很简单的例子来说明NDK的使用。我们在eclipse中新建一个android工程,其中:
    Project Name:jnitest
    Build Target: Android 1.6
    Application Name: JNI Test
    Package Name: org.eshock.jnitest
    Create Activity: JNITest

    JNITest.java:

    package org.eshock.jnitest;

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

    public class JNITest extends Activity {
        public native int plus (int x, int y);
        
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            int x = plus(1, 2);
            android.util.Log.d("jni", String.valueOf(x));
        }
        
        static {
            System.loadLibrary("mylib");
        }
    }

    我们只是演示NDK,所以就不要界面了。在这个程序中,我们调用一个c语言编写的plus(int, int)函数来计算1+2的值,然后在log中打印它。这个库的名称叫做mylib。
    要使用一个c语言的函数,需要在java中声明:
    public native int plus(int x, int y);
    这样java编译器就知道这个函数是外部库中实现的。

    C部分


    接下来我们使用C语言实现这个plus函数。
    创建<project>/jni/mylib.c:

    #include <string.h>
    #include <jni.h>

    JNIEXPORT jint JNICALL
    Java_org_eshock_jnitest_JNITest_plus( JNIEnv* env,
                                                      jobject thiz,
                                                      jint x,
                                                      jint y )
    {
        return x + y;
    }

    这 里我们看到,mylib.c里的plus函数比java里面的plus函数的签名要复杂了很多,主要是plus前面增加了包名,函数中多了两个参数,以及 所有的int变成了jint。关于c中类型与jni中类型的对应关系,可以参见jni的相关文档,例如core Java II中的最后一章。如果你不想去查阅文档,有一个方法:
    首先随便在某个目录下创建一个文件JNITest.java:

    public class JNITest {
        public native int plus (int x, int y);
    }

    然后在命令行下执行:
    javac JNITest.java && javah JNITest 
    将生成一个文件JNITest.h:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class JNITest */

    #ifndef _Included_JNITest
    #define _Included_JNITest
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     JNITest
     * Method:    plus
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_JNITest_plus
      (JNIEnv *, jobject, jint, jint);

    #ifdef __cplusplus
    }
    #endif
    #endif

    这里自动生成了java中native函数对应的签名,你可以在c代码中使用它。(记得修改包名)。

    Android.mk和Application.mk

    Android.mk是一个makefile,用来告诉NDK需要编译哪些文件,生成哪些模块。我们创建<jni>/Android.mk文件:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE    := mylib
    LOCAL_SRC_FILES := mylib.c

    include $(BUILD_SHARED_LIBRARY)

    其中LOCAL_PATH表示c源代码文件的位置;LOCAL_MODULE表示生成的共享库的名称;LOCAL_SRC_FILES代表c代码的文件。不需要把头文件列在里面;头文件的依赖关系是ndk自动计算的。

    Application.mk的作用是告诉Android SDK需要哪些库文件。有了它,NDK就可以把库放在正确的位置。我们创建<project>/Application.mk:

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

    APP_PROJECT_PATH代表android工程所在目录,在本例中它被放在<project>中; APP_MODULES表示工程需要的库,如果有多个以空格分开。

    编译共享库

    由于ndk规定Application.mk必须放在<ndk>/apps/project_name,我们在<ndk>下创建一个符号连接:
    ln -s <project> <ndk>/apps/jnitest
    这样,我们就可以开始编译共享库了:
    在<ndk>目录下运行:
    make APP=jnitest

    Android NDK: Building for application 'jnitest'
    Compile thumb  : mylib <= apps/jnitest/jni/mylib.c
    SharedLibrary  : libmylib.so
    Install        : libmylib.so => apps/jnitest/libs/armeabi

    可以看到编译成功,并在<project>/libs/armeabi/下生成了libmylib.so。

    测试

    在运行之前,首先确认一下你的工程里面各个文件都齐全,应该类似于这样:

    然后测试,正常的话应该能看到log中有输出3.

  • 相关阅读:
    python之fabric(二):执行模式(转)
    python之fabric(一):环境env (转)
    Javascript 将 console.log 日志打印到 html 页面中
    【nmon】nmon 服务器性能结果报告分析 —— 报表参数详解(转)
    Linux中搜索大于200M的文件
    Linux 创建用户和工作组
    saltstack执行state.sls耗时长的坑
    time命令_Linux time命令:测量命令的执行时间或者系统资源的使用情况(转)
    100种不同图片切换效果插件pageSwitch
    基于jQuery鼠标滚轮滑动到页面节点部分
  • 原文地址:https://www.cnblogs.com/xyzlmn/p/3168226.html
Copyright © 2011-2022 走看看