Netbeans玩转ndk
这两天研究了下ndk开发,因为公司android播放器,后续开发需要调用底层so库,网上查了很多资料全都是eclipse,但是我用的是netbeans只好自行研究,ndk很简单,baidu一下资料很多,如果你是一个有经验的程序员,分分钟就可以搞定,编译出一个so来。
主要问题就在于如何将so与apk打包到一起。
Eclipse是通过ADT插件自动完成的,也可以自己编写ant脚本,通过ant打包,这就不在本文范围内了。
1.1. 目的
让习惯netbeans的程序员,排斥eclipse的程序员能够顺利的完成他们的android开发,也让像学习ndk开发的人能够快速入门
1.2. 可能阅读者
有VC基础,想搞android开发的开发的技术人员
使用netbeans的android开发人员(一般也都是VC转过来的,因为VS IDE和NetbeansIDE风格比较相似)
2. 开发工具体系
Netbeans:
本教程使用的是6.8,但不限于6.8版本(自行下载安装)
用于开发android app
Ndk开发环境:
用于开发供app调用的so本地库
Windows开发环境包含以下2个软件包
n Ndk开发包android-ndk-r8d-windows.zip
下载链接http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip
如果打不开,可以进入下载页面
http://developer.android.com/tools/sdk/ndk/index.html#download下载
n Linux模拟环境cygwin
2.1. 搭建安装环境
第2步. 下载Ndk开发包
第3步. 解压到任意位置(本例:F:\ndk)目录结构如图
第4步. Ndk安装就完成了,该安装cygwin了
第5步. 下载cygwin.zip,这个是网络安装器,下载好有900多M就不打包在本教程中了
第6步. 安装cygwin,选择第一个,从网上下载安装,如图
第7步. 设置安装目录,如图
第8步. 设置下载到安装文件保存位置,如图
安装完成后,本地就有下载好的包,以后在别的机器重新安装时就可以选择第3项,从本地安装,选者这里设置的目录
第9步. 然后一直默认悬想,一直下一步,到如图步骤,选择一个下载站点,一般选择163速度还可以
第10步. 选择要安装的模块,只要安装Devel就够了,如图
第11步. 等待安装完成吧,大小是900多M
第12步. 验证cygwin安装
n 运行安装目录下的“Cygwin.bat”,第一次运行时,它会自动创建用户信息,用户信息存放在“.\Cygwin\home”中。
n 在运行“Cygwin.bat”打开的命令行窗口输入:“cygcheck -c cygwin”命令,会打印出当前Cygwin的版本和运行状态,如果status是ok的话,则cygwin运行正常。
n 分别输入:“make –v”和,“gcc –v”命令如果检测成功,会有make和gcc相关版本信息打印出来。
如图
第13步. Ndk开发环境搭建完成
第14步. 在系统环境变量中配置ndk目录(可选的操作,主要是为了方便),如图
cygwin是linux模拟环境,访问windows磁盘的方式是/cygdrive/盘符
2.2. 尝试编译一个so
直接使用附带jni例子
进入目录F:\ndk\\jni目录
编译hello-jni
编译后就会生成so文件了,这个文件就可以供android应用程序调用
2.3. 在netbeans创建的android项目中使用刚才编译出来的so本地库
第1步. 创建android项目calljni
第2步. 添加HelloJni类,代码如下
package com.example.hellojni;
public class HelloJni
{
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI();
/* 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");
}
}
第3步. 在MainActivity类中添加调用代码
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// ToDo add your GUI initialization code here
lib.stringFromJNI();
TextView tv = new TextView(this);
tv.setText( lib.stringFromJNI() );
setContentView(tv);
}
第4步. 将so文件添加到工程目录\lib\armeabi下,添加后so位置如图
第5步. Netbeans区别于eclipes的关键步骤
1) 编辑F:\ndk\calljni\nbproject\build-impl.xml文件
2) 找到name="-sign"的target, 也就是执行apkbuild的target
3) 在所有指令之前,加入以下指令,执行aapt将so打包进apk_
<exec executable="${aapt}" failonerror="true">
<arg value="a"/>
<arg value="${dist.apk}_"/>
<arg value="lib/armeabi/libhello-jni.so"/>
</exec>
如果有多个so需要打包进去,就多添加几条以上指令
这一步就是帮助netbeans的用户解决,如何把so文件打包进apk中这个难题。
大家都知道Apk就是一个zip格式的包,但是你不能直接将so文件打包进编译出来的apk中,因为apk是要签名才有效的,里面有签名文件如图中,打开查看,是通过hash算法计算出来的,所以必须在签名之前,把so文件打包进去一起签名,所以必须自己修改项目的编译脚本文件(其实就是ant编译脚本)。
第6步. 编译项目生成calljni.apk,在模拟器运行结果如图
2.4. ndk开发体系相关
1. 什么是NDK?
NDK 提供了一系列的工具,帮助开发者快速开发C/C++的动态库(so文件),通过mk 文件隔离CPU、平台、ABI 等差异,开发人员只需要简单修改mk 文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so,使你可以在你的Android程序当中用Java语言(JNI)调用这些c/c++代码.
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)
2. so文件必须使用ndk编译?
不是,可以直接在linux下编译so,但是你得确保你所使用的api是操作系统所支持,就是上面google声明中说的ndk支持的库,如果是特定平台支持的api,那可能就只有部分手机可以正常运行
3. mk文件如何编写
附件提供mk模板一分,可参考编写
4. 网上说的使用javah生成c/c++ .h文件,是否必须
不是,完全不需要,给出java生成.h文件的指令,和先决条件
javah -classpath ./build/classes -d jni org.me.calljni.MainActivity
首先必须编译java类,不管你用任何方式,编译出来就行,生成类.class文件,
然后使用以上指令生成头文件-classpath后面的目录就是生成的class的目录
5. java代码、c代码、so方法之间的联系
n 你的应用的java源代码中要声明一个或多个方法,这些方法前面需有'native'关键字,这表明它们被本地代码实现。如:
public native String stringFromJNI();
n 你必须提供本地的共享库(.so),库中包含这些方法的实现。将这个库打包你的.apk中。这个库的命名必须符合标准的Unix命名规则,也就是:lib<something>.so这种形式,例如:
libhello-jni.so。
n 并且还要包含一个标准的JNI入口,例如:
static {
System.loadLibrary("hello-jni");
}
n c函数生命应该按照如下规则命名,以说明函数是属于哪个java类的
java_目录_目录_方法名()例如:
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
以上函数,是一个java类的成员函数,这个类必须是在com\example\hellojni包下,类名必须是HelloJni
方法名必须是stringFromJNI(),没有参数
这是因为java是面向对象的语言,所以so中实现的所有全局函数应该是java的某个成员方法
n JNIEnv* env, jobject thiz
这2个参数是所有jni函数必须的,只有这2个参数的函数,表示无参数的成员函数,带有 3个参数就表示成员函数有1个参数,依次类推
n JNIEXPORT与JNICALL在提供android应用调用的so代码中不是必须的
加上兼容性更好
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz );
6. ndk能不能直接开发java类
不知道,未研究,有兴趣的可以深入研究,能够实现类成员函数,已经足够
7. so中能不能调用其它 .so或.a
理论上可以,但未验证,可以自行验证,如果是so,需要将so文件一起打包进apk,如果是.a文件,应该不需要打包进apk
8. ndk适合开发哪些模块
以下为个人理解
n 首先ndk未提供ui以及事件处理的api,所以做android开发不可能使用纯c/c++,应用主体应该还是android sdk使用java开发
n 其次so的反编译难度比android应用的java代码要难上很多,,所以ndk可以用于开发一些需要保密代码,防止反编译泄露机密算法逻辑等
n 观察ndk支持的库,可以看到,ndk适合做一些算法模块,提高效率,支持libc也可以实现通信模块,加强通信的安全性
转载于:https://my.oschina.net/u/732357/blog/106697