1..开发环境搭建:
NDK开发需要安装以下物体:
1.cygwin (需要1.7以上版本,下载地址:http://www.cygwin.com官方明确表示MSys or Cygwin 1.5 is notsupported)
在安装时候,选择make、gcc、g++、bash、
安装好后启动cygwin,运行:
看到如下所11示就ok了 (注意:GNU Make要 3.81以上版本)
3.NDK的使用
(android-ndk-r8b-windows),此文档只针对r8b版进行说明, ndk可以到官方网http://developer.android.com上进行下载
Ndk下载下来随意解压到一个目录即可(ndk的解压后存放的路径必须不能包括空格或中文,比如这种“D:\Program Files\Android-ndk-windows”在cygwin是不能识别成功的。)
如:D:\AndroidDevelop\NDK\android-ndk-r8b
配置NDK 在D:\AndroidDevelop\cygwin\home 目录下找到 .bash_profile 打开文件加上:
NDK=/cygdrive/d/AndroidDevelop/NDK/android-ndk-r8b
export NDK
配好后重新打开cygwin
输入:
cd $NDK
如出现如下提示表示路径已配好:
输入: $NKD/ndk-build 验证NDK是否可以使用?
如果出现以下信息说明已经配置成功!
在Cygwin下用nano或者vim编辑器编辑你的脚本。对于那些已经存在的脚本用dos2unix转化一下。因为Windows下的换行是<LF><CR>,Linux下是<LF>,Mac下是<CR>。
先对你的脚本跑一下 dos2unix .bash_profile 就行了。
配置NDK可以参照 http://www.linuxidc.com/Linux/2012-07/65388.htm
4.关于NDK简单的Demo
一。新建Android程序工程。
这里,我们需要做一下几步:
1.Layout中添加TextView的id。
2.MainActivity中声明native方法。
3.MainActivity中调用native方法。
我们这里先不loadLibrary。先load总感觉我的库还没有呢,先load做什么?有点莫名其妙。当然,你也可以先loadLibrary。看个人习惯了。
下面详细说明:
1.新建Android,名字,包名什么的随便取。一路下一步,生成之后,在默认生成的Activity的layout的TextView上加一个id。(这个都会吧)android:id="@+id/hello_jni"。此时的layout文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
TextView
android:id
=
"@+id/hello_jni"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/hello_world"
/>
</
RelativeLayout
>
|
2.在MainActivity.java中声明native方法。
public native String getHelloJniString();
3.在OnCreate()方法中获取TextView,并设置text。
((TextView)findViewById(R.id.hello_jni)).setText(getHelloJniString());
经过2、3两步之后的MainActivity.java文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.example.hellojni;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.widget.TextView;
public
class
MainActivity
extends
Activity
{
public
native
String getHelloJniString();
@Override
protected
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView)findViewById(R.id.hello_jni)).setText(getHelloJniString());
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return
true
;
}
}
|
二。生成.h头文件,编写.c文件。
这一步,你需要C/C++的语言基础。(这个简单的例子只需要简单的。)
按照大多数博客,会告诉你:编译工程之后,进入工程目录文件夹下,在控制台运行
javah -classpath bin/classes -d jni com.example.hellojni.MainAcitivity
,然后就会在工程目录下生成一个jni文件夹,里面就会有.h的头文件了。
实际上,你会遇到一个错误:
错误: 无法访问android.app.Activity
找不到android.app.Activity的类文件
是的,大多数人都会遇到这个问题,我对此表示疑问:那些写博客的人都自己试过没有?
怎么办呢?
1. 有人提出方法,在工程目录下运行命令:
javah -classpath src -d jni com.example.hellojni.MainAcitivity
就OK了。是的,这个是OK的。(这个命令和上面一个命令的区别就是 -classpath 不同了。)
2.还有一种方法:在工程目录下,上述命令中加上android.jar的classpath。也是可行的。也就是运行如下命令:javah -classpath F:\JNI\env\platforms\android-17\android.jar;bin/classes -d jni com.example.hellojni.MainActivity
这个命令,就是把android.jar的路径加了进去。这样,就能找到Activity类了。
以上两种可行的得到.h头文件的方法,生成的.h文件的内容是不一样的,你可以试试看。至于哪一种比较好,我目前还不清楚。因为看谷歌NDK的samples里面(samples这个文件夹,就是NDK的示例程序目录,对我们来说,就是教程了)的头文件,似乎是第一种方式。第二种方式倒是没有见到过。
我个人还是倾向于用第二种方式,虽然命令比较烦。。
多了一个jni文件夹和里面的一长串名字的头文件。名字太长,我们改短一点,改成HelloJni.h吧。省的麻烦。
接下来编写.c的实现文件。在jni文件夹右击,选择file,命名文件名字为HelloJni.c。确定。也就是如下:
然后打开新建的HelloJni.c文件,输入如下语句并保存:
1
2
3
4
5
6
7
8
|
#include <stdio.h>
#include "HelloJni.h"
jstring Java_com_example_hellojni_MainActivity_getHelloJniString
(JNIEnv * env, jobject clazz)
{
return
(*env)->NewStringUTF(env,
"Hello Jni!"
);
}
|
三。编写mk文件,使用Cygwin编译出so文件。
下面开始编写mk文件。在jni目录下创建一个Android.mk的文件(A要大写哦!!不然编译会出错:
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk /home/aditya/android-ndk-r9/build/core/add-application.mk:176: *** Android NDK: Aborting... .
)。加入如下代码并保存(里面的一些命令先不了解也是可以的。):
1
2
3
4
5
|
LOCAL_PATH := $(call my-
dir
)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloJni
LOCAL_SRC_FILES := HelloJni.c
include $(BUILD_SHARED_LIBRARY)
|
这里,主要注意两个地方:
LOCAL_MODULE := HelloJni 。这里的HelloJni就是你的库的名字,也就是你loadLibrary的字符串。生成出来的库是libHelloJni.so。
LOCAL_SRC_FILES := HelloJni.c 。这里的HelloJni.c就是c文件的名字。
下面打开Cygwin,进入到工程目录下,输入如下命令,并回车:
$NDK/ndk-build
出现如下画面,就说明ok了。
然后我们刷新工程,会发现,多了一个obj文件夹,和libs文件夹里面多了armeabi文件夹和里面的libHelloJni.so库。obj文件夹是没有用的,可以删掉了。
四。加载so文件,运行程序。
最后一步,我们再次进入MainActivity,加载库文件。加入后的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package
com.example.hellojni;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.widget.TextView;
public
class
MainActivity
extends
Activity
{
static
{
System.loadLibrary(
"HelloJni"
);
}
public
native
String getHelloJniString();
@Override
protected
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView)findViewById(R.id.hello_jni)).setText(getHelloJniString());
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return
true
;
}
}
|
System.loadLibrary("HelloJni"); 这个字符串就是我们在mk文件中写的LOCAL_MODULE的值。