‘壹’ “android NDK ”是什么,在什么情况下使用
1、NDK是一系列工具的集合。
2、NDK提供了一份稳定、功能有限的API头文件声明。
3、NDK的发布,使“java+C”的开发方式终于转正,成为官方支持的开发方式。
4、NDK将使Android平台支持C开发的开端。
NDK使得在android中,java可以调用C函数库。我们都知道,java是半解释型语言,很容易被反汇编后拿到源代码文件,在开发一些重要协议时,我们为了安全起见,使用C语言来编写这些重要的部分,来增大系统的安全性。还有,在一些接近硬件环境下,相信大家都清楚行袭升C与java的优劣。顺带提一下:NDK并不能显着提升应用效率。why?我们都觉得C语言比起java来说效率要高出很多,一方面,随着jdk的不断更新,java的效率也随之提高;另一方面,即便使用C语言编码提高了应用效率,但是在java与C相互调用时平白又增大了开销。
‘贰’ 如何从零开始创建Android NDK应用
本文主内容:
1、 Android NDK 安装
2、 安装Cygwin与使用NDK编译
3、 在Eclipse中集成C/C++开发环境CDT
4、 安装Sequoyah插件
5、 JNI编译环境配置
本文建立在已经完成Android开发环境搭建的基础上。其基础环境至少需要包含以下内容:
1、 JDK
2、 Eclipse
3、 Android SDK and ADT
可以参考我之前的“Android开发环境搭建”。
一、Android NDK 安装与配置
下载Android NDK。下载地址:http://developer.android.com/tools/sdk/ndk/index.html
下载后解压缩到你的工作目录,例如:D:\Java\android-ndk-r8,结果如下图:
注意:samples下面包含几个实例开发演示项目,第一次接触NDK开发,建议先从示例开始。
docs内是技术文档,英语能力强的可以研究研究。
二、安装Cygwin与使用NDK编译
由于NDK开发大都涉及到C/C++在GCC环境下编译、运行,所以在Windows环境下,需要用Cygwin模拟linux编译环境。
下载:
Cygwin的下载地址:http://www.cygwin.com/
点击右上角的“setup.exe”即可下载。
安装:
第一步:运行setup.exe程序,直接点击Next进入下一步。
第二步:选择安装方式。第一次可以采用Direct Connection在线下载安装,如有现成的离线包,可以选择离线安装(Install from Local Directory)。
第三步:选择安装目录。比如D:\Java\Cygwin,注意此目录是指Cygwin最终的安装目录,不是下载文件暂存目录。
第四步:设置本地包暂存路径。暂存目录默认是放到setup.exe的同级目录下,建议放到指定的文件夹,如D:\Cygwin_install_file。安装完成后把这个文件夹打包备份,以后再配置时不用重新下载。
第五步:设置网络连接方式。这个目前河蟹没爬过来,选第一个即可。
第六步:选择下载站点地址。据说国内163站点的速度不错,我也是用的这个。
第七步:等待加载安装项载入,选择安装项。点击Devel-Default,使之变成Devel-Install,展开后可以看到其下的子项被选中了(网上多数教程都说选中某12个包,找起来太坑爹了,直接全下载了吧,全选多了150M左右)。此界面其他设置都不用动。
第八步:等待下载完成。下载完成时间决定于你选择的安装包数量及网络连接速度,安装我安装的版本,约983M,下载完成后会自动安装到上文设置的安装目录,安装也要时间的,总时间较长,去吃个饭没啥问题。
提醒:第四步的备份建议,尽量去做。如果有备份,第二步中选择离线安装。
验证:
运行安装目录下的“Cygwin.bat”,第一次运行时,它会自动创建用户信息,用户信息存放在“.\Cygwin\home”中。
在运行“Cygwin.bat”打开的命令行窗口输入:“cygcheck -c cygwin”命令,会打印出当前Cygwin的版本和运行状态,如果status是ok的话,则cygwin运行正常。
分别输入:“make –v”和,“gcc –v”命令如果检测成功,会有make和gcc相关版本信息打印出来。
设置NDK路径:
在windows的系统环境变量中添加NDK的路径。使用“/cygdrive/d/Java/android-ndk-r8”这种Linux风格路径,如果使用Windows下的“D:\Java\android-ndk-r8”,Cygwin在编译时会发出警告。
运行Cygwin命令行,可以直接使用此环境变量,当然也可以手动的cd到该目录:
使用NDK编译程序:
现在我们用安装好的NDK来编译一个NDK提供的sample程序hello-jni(我的目录位于:D:\Java\android-ndk-r8\samples\hello-jni)。
第一步:运行Cygwin,配置环境变量后可输入“cd $ndk/samples/hello-jni/”,未配置则输入命令“cd /cygdrive/d/java/android-ndk-r8/samples/hello-jni”,进入到“hello-jni”工程目录。
第二步:编译。输入命令“$ndk/ndk-build”命令即可编译。ndk-build是调用ndk的编译程序。
关于下面的错误,我没遇到,但是前人有总结,记录如下:
错误:Android NDK: Host 'awk' tool is outdated。
解决方法:打开目录“D:\Java\android-ndk-r8\prebuilt\windows\bin\”,删除awk.exe(为保险起见请先备份)。
第三步:到”…/hello-jni/libs/armeabi“目录下看有没有生成的.so文件,如果有,你的ndk就运行正常啦!
导入NDK的hello-jni示例到Eclipse中:
第一步:在Eclipse中新建一个Android工程HelloJni。在Create Android Project时勾选“Create project from existing source”,Location中填“D:\Java\android-ndk-r8\samples\hello-jni” (注意:在选择API level时需要选择1.5或更高的版本)。
第二步:直接以Android Aplication运行。这里要注意,你之前在使用NDK编译程序时要把这个hello-jni编译过并产生了.so文件,此处才能运行起来。
三、在Eclipse中集成C/C++开发环境CDT
CDT的安装可以使我们在一个工程中,同时开发基于C/C++的Native代码和基于Java语言的壳,之后的配置还可以使得一次编译两部分代码。
下载:
下载地址:http://www.eclipse.org/cdt/downloads.php
说明:
Eclipse C/C++ IDE Indigo SR2:是带CDT的Eclipse开发环境。
p2 software repository:在线安装的地址。(似乎被河蟹爬了)
cdt-master-8.0.2.zip:这个是CDT的离线安装包。(推荐使用这个,保留离线包,复用)
离线安装:
Eclipse -> Help -> Install New Software,点击add。Name:随意,建议使用好记的“CDT_版本”。Location:点击Archive,定位到下载的“cdt-master-8.0.2.zip”文件。
错误:
如果Location的下面出现“Duplicate location”错误,请到Window -> preferences -> Install/Update -> Avaliable Software Site中找到该条,remove之。
验证:
安装完成后,在Eclispe中新建一个项目,如果出现了C/C++项目,则表明CDT插件安装成功了。
四、安装Sequoyah插件
Sequoyah插件用于设置Android工程对Native开发的支持。
官方网址:http://www.eclipse.org/sequoyah/downloads/
在线安装:
官网提供了用于在线安装的Update Site地址以及安装包的下载地址。貌似安装包才1M多,在线安装也没被河蟹爬过,直接在线安装了。勾选全部列出的可安装项并完成安装。
Location:http://download.eclipse.org/sequoyah/updates/2.0/
注意:
在安装界面不要勾选“Group items by category”复选框,默认是勾选的,出现了列表为空(There are no categorized items)的情况。
配置:
安装完Sequoyah插件后,为Android配置NDK路径。
在“window –> preferences ->Android -> 本机开发”中添加NDK的路径。
验证:
右键之前建立的“HelloJni”项目,在“Android Tools”选项中包含“Add Native Support…”选项即成功。
五、JNI编译环境配置
仍旧以之前建立的“HelloJni”为例,到目前为止,如果我们修改“/HelloJni/jni/hello-jni.c”文件,动态链接库libhello-jni.so文件却不会被重新编译生成。这是因为我们没有给JNI项目添加它需要的编译配置和依赖库。现在我们来配置它。
第一步:转换工程。点击“文件 -> 新建 -> 其他”(快捷键:Ctrl+N)。选择“C/C++”下的“Convert to a C/C++ Project(Adds C/C++ Nature)”。进入“下一步”。
第二步:选中你刚才建的“HelloJni”工程,下面左边选“Makefile project”右边选“Cygwin GCC”。确定后提示的“透视图”不清楚是什么,点击“是”即可。
第三步:在“HelloJni”工程上右键,选择“属性”。配置“C/C++ Build”和“C/C++ General -> Paths and Symbols”。
C/C++ Build:点击“C/C++ Build”,在右边的“Builder Settings”中去掉默认勾选的“Use default build command”复选框。设置Build command为“bash D:\Java\android-ndk-r8\ndk-build”。
C/C++ General -> Paths and Symbols:在Includes下add新的GNU C依赖路径。此“HelloJni”工程需要“D:\Java\android-ndk-r8\platforms\android-8\arch-arm\usr\include”即可,以后根据不同项目选择不同的依赖库。
验证:
将“/HelloJni/jni/hello-jni.c”中的字符串“Hello from JNI !”如改为“Hello JNI from Baron!”,运行后在模拟器上输出的字符串改变即说明配置成功。
‘叁’ AndroidStudio怎样使用NDK开发示例
1、新建一个Android工程,这一步就不多说了;
2、在AndroidStudio中配置NDK路径,方法是:
(1)先下载NDK并安装(这句基本是废话);
(2)点菜单栏的File->ProjectStructure…->在打开的窗口中左侧选中SDKLocation->在右侧Android NDK Location中填入NDK目录所在路径
3、编译生成.class文件,方法是:
点菜单栏的Build->Make Project
这时,在工程的app/build/intermediates下就会生成classes文件夹,打开classes目录下的debug目录就会看到以你的包名命名的各级文件夹,最里边文件夹下有你的Java类对应的.class文件;
4、确定你要引用本地方法的类:
其实你也可以先生成jni目录,再去创建这个类,但是先Google显然建议先创建要引用C代码的Java类,因为AndroidStudio可以根据你在java类中定义的native方法的名称来自动生成.h头文件。
比如你想在MainActivity中引用本地方法,那么你先用
static {
System.loadLibrary("myNativeLib");
}
来声明本地代码库,然后定义几个natvie方法,比如
public native String getStringFromNative();
5、使用javah命令行生成jni目录及对应的头文件:
我用的是AndroidStudio 2.1.1,在主界面最下边就能找到Terminal,点一下就能打开系统的命令行工具,并且已经为你自动cd到当前工程所在目录
6、配置build.gradle文件
这里的build.gradle是指app模块下的build.gradle,不是整个工程的build.gradle文件。在模块的build.gradle的defaultConfig下加入以下idk配置:
ndk {
moleName"myNativeLib"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
7、配置local.properties文件
打开工程目录下的local.properties,感觉这一步是自动配置的,或者说在你一开始在AndroidStudio中指定NDK目录时已经自动生成了。我的AndroidStudio在打开local.properties已经有了
ndk.dir=/Develop/Android/android-ndk-r10e
这一行,所以就不用配了;
8、配置gradle.properties
打开工程目录下的gradle.properties文件(注意不是build.gradle,而是gradle.properties),在文件的最后一行加入
android.useDeprecatedNdk=true
这句的作用是允许我们使用已经过时的NDK版本,不知道AndroidStudio要求使用哪个版本的NDK才不会报错,总之只要配置了这一句就可以使用比较旧的NDK版本了,我用的r10;
至此我们在AndroidStudio中就完成了NDK环境的配置,接下来就可以写Native代码了;
9、写一个.c文件测试一下是否运行正常
(1)在我们之前生成src/main/jni目录下新建一个.c文件,方法是在jni文件夹上点鼠标右键,选择New->C/C++ Source File,然后在弹出的对话框中填入.c或.cpp文件的文件名就可以了,比如说mail.c
‘肆’ android ndk 开发只写jni层的代码吗不能写hal层的代码吗以及linux驱动模块的代码嘛
NDK开发可以linux下的android源码中编译单个模块生成.so文件,然后放在上层android 项目中调用,你在源码中吧,你要编译的模块驱动的C代码放进去,按照JIN规则取号名字,然后编\编译,就行了,把生成的 so文件导入到上层项目,然后你知道C的函数名,在java层写本地方法和,C的函数名一样,记得类名也别搞错了,就行了。不要烧录整个系统,只要编译你需要的驱动模块生成so文件就行
‘伍’ 如何使用android的ndk建立native的开发环境
从网上看了一篇使用andriod的toolchain在cygwin上来建立android的开发环境,但是在vista上编译始终失败,在xp上能够成功。但是编译的时间比较长,而且对于新手来说也比较麻烦,难道就没有简单的方法吗?google已经把andriod的ndk已经放出来了,所以我就想着打它的主意了,把它配置一下,就能来开发c的程序了。旁边小伙肯定笑了,“搞啥?,有病啊,ndk就是一个开发native code的环境。”大哥,我当然知道了,虽然使用ndk来开发native code相对容易,但是它的.mk文件我看的是云里雾里,我本来想调用自己写的另外一个so库,都不知道在.mk文件里如何写,我现在也懒的去看ndk里面的mk文件,等哪天(哪天?天晓得是哪一天)有空了好好研究一下。好了,闲话少说,开练吧。首先安装cygwin,这个网上的教程多的是,就不说了,接着下载android ndk,这个在andriod的官网上就有了,然后下载一个从android模拟器里取system lib的工具busybox,然后调用命令
$adb push busybox /dev/sample/busybox
$adb shell chmod 777 /dev/sample/busybox
$adb shell ./dev/sample/busybox tar -cf /dev/sample/libs.tar /system/lib
$adb pull /dev/sample/libs.tar libs.tar
这样就将模拟器下的 /system/lib 目录的所有库(so)文件打包并下载下来了,解压libs.tar就得到了我们所需要的所有库文件。
接着将所有的文件 到 $(NDK)/build/prebuilt/windows/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1,好了,这个时候基本的配置工作就结束了,怎么样简单多了吧。
接着编写一个简单的c文件 tutorial01.c
#include <stdio.h>
int getinformation()
{
return 0;
}
然后编写一个Makefile文件
CC = /cygdrive/f/software/android/android-ndk-1.5_r1/build/prebuilt/windows/arm-eabi-4.2.1/bin/arm-eabi-gcc
CFLAGS = -g -O2 -fPIC -DANDROID -I ./ -I ../ -I F:/software/android/android-ndk-1.5_r1/build/platforms/android-1.5/arch-arm/usr/include
SDFLAGS = -nostdlib -Wl,-T,armelf.xsc -Wl,-soname,$@ -Wl,-shared,-Bsymbolic -lc
CRT_OBJS= -lz -lm
all: libtutorial01.so
libtutorial01.so: tutorial01.o
$(CC) $(SDFLAGS) -o $@ tutorial01.o $(CRT_OBJS)
tutorial01.o: tutorial01.c
然后make,这个时候会报错 can't find "armelf.xsc", 在ndk的目录里搜索一下,搜到之后 到$(NDK)/build/prebuilt/windows/arm-eabi-4.2.1/lib/gcc/arm-eabi/4.2.1,然后make,成功。这样一个简单的so文件就生成了,这个时候如果想在android的虚拟机上运行,我们还需要给它包装一下。再编写一个文件test01.c,在这里是使用dl动态加载so文件,静态加载始终有问题,搞不清楚android是如何搜索目录,而且现在只能用绝对路径,这个问题还得仔细研究研究。
#include <string.h>
#include <jni.h>
jint
Java_com_example_testffmpeg_testffmpeg_getinformation( JNIEnv* env,
jobject thiz )
{
void* filehandle = dlopen("/data/data/com.example.test/lib/libtutorial.so", RTLD_LAZY );
int ll = -1;
if(filehandle)
{
int( * getinformation ) ();
getinformation = dlsym(filehandle, "getinformation");
if( getinformation )
{
ll = getinformation();
}
else
{
ll = -3;
}
dlclose(filehandle);
filehandle=0;
}
else
{
ll = -2;
}
return ll;
}
同样再来一个Makefile文件
CC = /cygdrive/f/software/android/android-ndk-1.5_r1/build/prebuilt/windows/arm-eabi-4.2.1/bin/arm-eabi-gcc
CFLAGS = -g -O2 -fPIC -DANDROID -I ./ -I ../ -I F:/software/android/android-ndk-1.5_r1/build/platforms/android-1.5/arch-arm/usr/include
SDFLAGS = -nostdlib -Wl,-T,armelf.xsc -Wl,-shared,-Bsymbolic -Wl,-soname,$@ -lc -L ../tutorial
CRT_OBJS= -lz -lm -ldl
all: libtest01.so
libtest01.so: test01.o
$(CC) $(SDFLAGS) -o $@ test01.o $(CRT_OBJS)
ok, make一下成功。好了,接下来使用andriod的sdk写一个简单的activity, testapp来测试其运行情况,以下是test01.java的代码。
package com.example.test;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public class test01 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() );
Integer ll = getinformation();
String lls = ll.toString();
tv.setText(lls);
setContentView(tv);
}
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native int getinformation();
/* 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("test");
}
}
在eclipse中运行,在模拟器上显示0,就表示成功了。
‘陆’ android ndk与sdk
1. SDK
Android SDK(Android Software Development Kit),即Android软件开发工具包,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”,也就是说我们还可以采用C/C++语言。
2. NDK
NDK即Native Development Kit,众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。
NDK是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk(AndroidPackage的缩写,Android安装包)。这些工具对开发者的帮助是巨大的。它集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。它可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作
NDK提供了一份稳定、功能有限的API头文件声明,Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
为什么使用NDK
(1) 代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
(2) 可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
(3) 提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
(4)便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。