ADT Eclipse编译Android NDK的so库详解

发表于

谭东编写。

NDK全称:Native Development Kit。

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。

NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

NDK提供了一份稳定、功能有限的API头文件声明。

Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。

对于Windows环境下NDK的开发,如果使用的NDK是r7之前的版本,必须要安装Cygwin才能使用NDK,所以为Eclipse需要配置的builder,其实是执行Cygwin,然后传递ndk-build作为参数。在NDKr7开始,Google的Windows版的NDK提供了一个ndk-build.cmd的脚本,这样,就可以直接利用这个脚本编译,而不需要使用Cygwin了。只需要为Eclipse Android工程添加一个Builders,就能让Eclipse自动编译NDK。

这里我们使用ADT进行配置ndk编译环境,然后编译出so库。

1、下载ndk。http://developer.android.com/ndk/downloads/index.html#download

然后解压到硬盘上任意目录下即可。

2、打开ADT(Eclipse),新建一个工程(这里叫HelloJni)。工程目录下新建jni目录,jni文件夹就是放要编译的c/c++等代码。

20160324104707

3、新建并配置一个Builder。打开Project->Properties->Builders->New,新建一个Builder。弹出框里选择Program。

20160324104857

Builder名字我这里叫Ndk_bulder。先配置Main选项卡:在“Location”中输入nkd-build.cmd的路径。点击“Browser File System…”来选取这个路径。

在“Working Diretcoty”中输入${workspace_loc:/HelloJni}(也可以点击“Browse Workspace”来选取HellonJni(要编译的项目)的目录)。

20160324105037

接下来配置Refresh选项卡:

如下图勾选即可。

20160324105044

接下来配置Build Options选项卡:

如下图配置。

20160324105104

点击“Specify Resources…”
勾选HelloJni工程的“jni“目录,点击”finish“。
点击“OK“,完成配置。
OK,到这里Eclipse就能够自动调用NDK编译jin目录下的C/C++代码了。

20160324105058

4、将hello-jni.c放到jni目录下。

 


/*
 * 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_whatjay_hellojni_MainActivity_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
#if defined(__arm__)
  #if defined(__ARM_ARCH_7A__)
    #if defined(__ARM_NEON__)
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a/NEON (hard-float)"
      #else
        #define ABI "armeabi-v7a/NEON"
      #endif
    #else
      #if defined(__ARM_PCS_VFP)
        #define ABI "armeabi-v7a (hard-float)"
      #else
        #define ABI "armeabi-v7a"
      #endif
    #endif
  #else
   #define ABI "armeabi"
  #endif
#elif defined(__i386__)
   #define ABI "x86"
#elif defined(__x86_64__)
   #define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
   #define ABI "mips64"
#elif defined(__mips__)
   #define ABI "mips"
#elif defined(__aarch64__)
   #define ABI "arm64-v8a"
#else
   #define ABI "unknown"
#endif

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

编写Android.mk。


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := hellojni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)

编写Application.mk。


APP_ABI :=all

表示全平台CPU架构so库编译。

两个.mk文件都放在jni目录下。

5、编写MainActivity.java代码:


package com.whatjay.hellojni;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

    private TextView tv_name;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_name=(TextView) this.findViewById(R.id.tv_name);
        tv_name.setText(stringFromJNI());
    }

    public native String stringFromJNI();

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

}

运行即可。会自动编译各个平台so库。

20160324111217

20160324111228

6、使用编译好的so库。

新建Android项目,并且要使用该so库的类名和所在包名要和so库里编译时一致。

将so库和架构文件夹拷贝到libs目录里即可。

20160324114313

编写MainActivity.java调用。


package com.whatjay.hellojni;

import com.whatjay.hellojin2.R;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
    private TextView tv_name;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_name=(TextView) this.findViewById(R.id.tv_name);
        tv_name.setText(stringFromJNI());
    }
    public native String stringFromJNI();

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

编译生成APK即可。

 

谭东编写。


文章评论
共收到 0 条评论