对于还不了解Android NDK作用和搭建的朋友,可以先参考下Android NDK作用与搭建,今天这篇文章是建立在已经搭建好Android NDK开发环境,来看看NDK编程 "Hello Jni"的实现。


首先Android NDK开发需要具备哪些基础知识?

1.熟悉Android应用开发

2.熟悉C语言(编写底层.so库需要用到)

3.了解Linux(要知道一些常用的命令)


下面打开NDK包下Sample目录下的“hello-jni”例子工程

android ndk armeabi 可以删除吗 android ndk作用_Java


如上图可以看到,就是一个普通Android应用程序,在Src目录里有个HelloJni.Java程序,不同的是多了一个“jni”目录,JNI(Java Native Interface,中文为JAVA本地调用),JNI的作用:可以通过Java程序访问到其他语言(主要是C/C++)写出来的库(linux平台.so库,Windows平台.dll库),其中NDK会通过“.mk“文件将“hello-jni.c”C语言文件编译成需要的.so库,默认情况下“.mk“文件不需要修改,有兴趣的朋友可以百度下JNI更多相关资料。


下面将此例子代码导入到eclipse中,刚开始研究时只用导入第一个HelloJni项目就行了

android ndk armeabi 可以删除吗 android ndk作用_Java_02


先看看HelloJni.Java

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.hellojni;

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


public class HelloJni extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        /* Create a TextView and set its content.
         * the text is retrieved by calling a native
         * function.
         */
        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }

    /* A native method that is implemented by the
     * 'hello-jni' native library, which is packaged
     * with this application.
     */
    public native String  stringFromJNI();

    /* This is another native method declaration that is *not*
     * implemented by 'hello-jni'. This is simply to show that
     * you can declare as many native methods in your Java code
     * as you want, their implementation is searched in the
     * currently loaded native libraries only the first time
     * you call them.
     *
     * Trying to call this function will result in a
     * java.lang.UnsatisfiedLinkError exception !
     */
    public native String  unimplementedStringFromJNI();

    /* this is used to load the 'hello-jni' library on application
     * startup. The library has already been unpacked into
     * /data/data/com.example.hellojni/lib/libhello-jni.so at
     * installation time by the package manager.
     */
    static {
        System.loadLibrary("hello-jni");
    }
}

我们先知道这行代码System.loadLibrary("hello-jni");就可以访问到“hello-jni.c”文件编译后的.so库,然后tv.setText( stringFromJNI() );就可以调用到“hello-jni.c”C文件中的函数。

这行代码public native String  stringFromJNI();表示接口的申明,返回字符串。直接映射到了C文件中的调用函数。


接着看下hello-jni.c

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <string.h>
#include <jni.h>

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #define ABI "armeabi-v7a/NEON"
    #else
      #define ABI "armeabi-v7a"
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__mips__)
   #define ABI "mips"
#else
   #define ABI "unknown"
#endif

    return (*env)->NewStringUTF(env, "huahua Hello from JNI !  Compiled with ABI " ABI ".");
}

对Java_com_example_hellojni_HelloJni_stringFromJNI函数返回的字符串做了一点小小的修改,其中函数第一个参数 JNIEnv是Google所提供的用于Java和C交互的一种结构,结构的细节暂时不去深究,先知道通过return返回这行代码的语法就可以把某项内容返回给来自于Java文件的调用者stringFromJNI()。


这里可能会有疑问stringFromJNI()和Java_com_example_hellojni_HelloJni_stringFromJNI()两个方法的名字不一样,其实C文件中最后一个"_"后面的名字就是Java中调用的接口的名字,前面则是包名的结构,这种写法的原因是来自gcc编译器的,而且是有固定规则。


下面直接在手机上运行下工程,出现弹错!,logcat信息如下

android ndk armeabi 可以删除吗 android ndk作用_Android_03

 


因为现在.so库还不存在呢,需要我们自己通过mk文件,C文件编译出来。打开控制台,进入到E:\android-ndk-r9d\samples\hello-jni\jni目录,输入ndk-build

android ndk armeabi 可以删除吗 android ndk作用_Android_04

 

ndk-build这个脚本程序会完成编译,生成.so库等等一切的相关工作,执行完后在工程下多了"libs"和"obj"2个子目录,

在libs中会根据不同CPU硬件生成各自的.so库,这个暂时不用去深究。

android ndk armeabi 可以删除吗 android ndk作用_Java_05

这时刷新一下eclipse中的工程,libs中的.so库就加入进去了,运行程序效果如下

android ndk armeabi 可以删除吗 android ndk作用_Java_06

 

说明上层Java程序调用底层.so库中的函数OK,这样一个简单的JNI调用就完成了。

 

我们再看下在HelloJni.Java中

static {
         System.loadLibrary("hello-jni");
     }

这个语法表示在类加载时,就会调用System.loadLibrary("hello-jni");,去加载hello-jni这个库。这个名字在代码中是这样写,在实际中linux平台中左边会多上lib3个字母,右边会多上.so。其实就是我们编译出来的libs目录中的libhello-jni.so库。如果在Windows平台下右边会是.dll。库个名称和程序中写的是相互对应的,这是由操作系统规定必须这样写的。