NDK浅尝(1)

来源:转载

First JNI Project

这篇博客主要针对Android NDK开发做入门级阐述,所涉及到的主要有以下几点:

  • Android NDK开发简介
  • JNI简介
  • 工具介绍
  • 构建HelloJNI项目

1.Android NDK开发简介
Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。NDK包括了:

  1. 从C / C++生成原生代码库所需要的工具和build files
  2. 将一致的原生库嵌入可以在Android设备上部署的应用程序包文件
  3. 将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application packages files ,即.apk文件)中。
  4. 支持所有未来Android平台的一些列原生系统头文件和库

2.JNI简介
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java 虚拟机环境下。更多相关细节参见百度百科


3.工具介绍

  1. NDK
  2. SDK
  3. Android Studio 1.4
    稍后将会用专页共享各项软件的下载链接及安装。

4.构建HelloJNI项目

等不到我开发环境构建的兄弟们可以先根据其他博客自己搭建环境,相对而言环境相关的教程是比较多的,本篇博客的主要目的在于引导大家在最新环境上入手JNI开发:
第一步: 新建Android项目
新建的Android项目路径如下图所示:

第二步:
添加JNI文件荚
右键->new->Folder->JNI Folder,添加后文件目录如图所示:

第三步:
在jni文件夹上右键new ->file,命名为Android.mk,同上再新建一个hello-jni.cpp文件。Android.mk文件内容如下:

#一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)#CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),#除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。#编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。#编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'hello-jni'的共享库模块,将会生成'libhello-jni.so'文件。#如果你把库命名为‘libhello-jni’,编译系统将不会添加任何的lib前缀,也会生成 'libhello-jni.so',这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。#LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。#默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)#BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。#LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := hello-jniLOCAL_SRC_FILES := hello-jni.cppinclude $(BUILD_SHARED_LIBRARY)

hello-jni.cpp文件内容如下所示:

#include <jni.h>#include <string.h>//extern "C" 标记该函数为C,因为JNI linker不能遵照从C++的命名规则,如果不加这一句,JNI linker会把它当作c++函数,在真机或者模拟器运行时报Unsatisfied Linker的错误extern "C" JNIEXPORT jstring JNICALL Java_com_tt_hellojni_MainActivity_NDKTestFromJNI( JNIEnv* env, jobject thiz ){ return env->NewStringUTF( "Hello from JNI !");}

完成后,项目目录如下:

接着打开MainActivity.java文件,修改其内容如下:

import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.TextView;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText(NDKTestFromJNI()); setContentView(tv); } public native String NDKTestFromJNI();// native声明,表示这个方法来自Native层。实现过程已经在native层实现了 static { System.loadLibrary("hello-jni");// 加载库,前面的lib和后缀名不用写 }}

第四步: 打开terminal,依次按图中输入命令操作

此时,我们就可以看到生成的.so文件了哈,如下图所示:

第五步: 执行项目,运行在真机上,界面上会显示

Hello from JNI !


分享给朋友:
您可能感兴趣的文章:
随机阅读: