android下NDK开发环境搭建及TestJNI入门实例完整过程
来源:互联网 发布:php平台是干什么用呢? 编辑:程序博客网 时间:2024/04/30 01:23
1.先搭建好基本的ndk的开发环境
在windows下安装下面两个软件
1、 Android NDK 安装
2、 安装Cygwin与使用NDK编译
本文建立在已经完成Android开发环境搭建的基础上。其基础环境至少需要包含以下内容:
1、 JDK
2、 Eclipse
3、 Android SDK and ADT
一、Android NDK 安装与配置
下载Android NDK。下载地址:http://developer.android.com/tools/sdk/ndk/index.html
下载后解压缩到你的工作目录,例如:D:\Java\android-ndk-r8,结果如下图:
注意:samples下面包含几个实例开发演示项目,第一次接触NDK开发,建议先从示例开始。
二、安装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到该目录:
三、新建TestJni工程,使用NDK编译程序
1.创建Android工程
2首先建立一个名为TestJni的Android工程,包名默认为com.example.hellojni,src目录下自动创建MainActivity.java。
设计JNI接口,新建一个java文件,TestJni.java.如图
—工程目录图
TestJni.java代码如下
package com.example.hellojni;public class TestJni { public native boolean init(); public native int add(int x,int y); public native void destory();}
3.编译JNI
在E:\workplace\TestJni\bin\classes\com\example\hellojni文件夹下会生成TestJni.class文件。
在bin文件夹下,如果没有则创建目录:/com/example/jni,并把TestJNI.class复制到/bin/com/example/jni目录下。然后在终端里进入工程的bin目录,输入javah -jni com.example.jni.TestJNI,此时会生成一个com_example_jni_TestJNI.h文件。
注意:我在输入javah -jni com.example.jni.TestJNI的命令时会出错,改为
javah -classpath E:/software_tool/android/adt-bundle-windows-x86_64-20140702/sdk/platforms/android-20/android.jar;bin/classes -d jni com.example.hellojni.TestJni
4.用C/C++实现JNI
有了JNI的C/C++头文件,就可以在C层实现JNI接口了。首先在工程目录下创建一个jni目录,这个目录就是专门用来放C/C++代码的。把com_example_hellojni_TestJni.h文件复制到jni目录下,并在这里创建一个com_example_jni_TestJni.cpp文件。
由于我想用C++来实现JNI,所以上面两个文件我只是用来作为动态链接库的接口,具体的实现我希望放在一个类里面来完成,因此我再添加两个文件:Add.h和Add.cpp。如上操作结果见工程目录图
com_example_hellojni_TestJni.h
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_hellojni_TestJni */#ifndef _Included_com_example_hellojni_TestJni#define _Included_com_example_hellojni_TestJni#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_hellojni_TestJni * Method: init * Signature: ()Z */JNIEXPORT jboolean JNICALL Java_com_example_hellojni_TestJni_init (JNIEnv *, jobject);/* * Class: com_example_hellojni_TestJni * Method: add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_example_hellojni_TestJni_add (JNIEnv *, jobject, jint, jint);/* * Class: com_example_hellojni_TestJni * Method: destory * Signature: ()V */JNIEXPORT void JNICALL Java_com_example_hellojni_TestJni_destory (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
com_example_hellojni_TestJni.cpp
#include <stdio.h>#include <stdlib.h>#include "com_example_hellojni_TestJni.h"#include "Add.h"CAdd *pCAdd = NULL;JNIEXPORT jboolean JNICALL Java_com_example_hellojni_TestJni_init(JNIEnv *env,jobject obj) { if (pCAdd == NULL) { pCAdd = new CAdd; } return pCAdd != NULL;}JNIEXPORT jint JNICALL Java_com_example_hellojni_TestJni_add(JNIEnv *env, jobject obj, jint x, jint y) { int res = -1; if (pCAdd != NULL) { res = pCAdd->add(x, y); } return res;}JNIEXPORT void JNICALL Java_com_example_hellojni_TestJni_destory(JNIEnv *env, jobject obj){ if (pCAdd != NULL) { pCAdd = NULL; }}
Add.cpp
#include "Add.h" CAdd::CAdd() { } CAdd::~CAdd() { } int CAdd::add(int x, int y) { return x + y;}
Add.h
#ifndef _TEST_JNI_ADD_H_#define _TEST_JNI_ADD_H_class CAdd { public: CAdd(); ~CAdd(); int add(int x,int y);};#endif
到此C/C++代码实现结束
5、创建Android.mk
JNI实现了之后就要把C/C++代码编译成动态链接库.so文件,这样Java程序才能调用JNI的接口。要编译so文件,需要写Android.mk和Application.mk两个文件。我们先来写Android.mk。
先在工程目录的jni下创建一个Android.mk文件:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := TestJniLOCAL_SRC_FILES := com_example_hellojni_TestJni.cppLOCAL_SRC_FILES += Add.cppinclude $(BUILD_SHARED_LIBRARY)
其中LOCAL_PATH是C/C++代码所在目录,也就是我们的jni目录。
LOCAL_MODULE是要编译的库的名称。编译器会自动在前面加上lib,在后面加上.so。
LOCAL_SRC_FILES是要编译的C/C++文件。
现在我们在工程的根目录下创建一个Application.mk文件,并输入如下内容:
APP_PROJECT_PATH := $(call my-dir)APP_MODULES := TestJni
6、编译动态链接库(.so文件)
默认在Windows7下配置好了NDK开发环境,打开cygwin,进入到工程目录
编译生成.SO库
编译成功后会在工程目录的libs/armeabi目录下生成一个libTestJni.so文件。
7 在Java中调用JNI
现在我们的Android应用可以调用JNI计算加法的代码,如下:
MainActivity.java
package com.example.hellojni;import android.support.v7.app.ActionBarActivity;import android.app.Activity;import android.app.SearchManager.OnCancelListener;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends Activity{ static{ System.loadLibrary("TestJni"); } EditText tvX = null; EditText tvY = null; EditText tvSum = null; Button btnAdd = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvX = (EditText)findViewById(R.id.et_x); tvY = (EditText)findViewById(R.id.et_y); tvSum = (EditText)findViewById(R.id.et_sum); btnAdd = (Button)findViewById(R.id.btn_add); btnAdd.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub int x = Integer.valueOf( tvX.getText().toString()); int y = Integer.valueOf( tvY.getText().toString()); int sum = 0; TestJni jni = new TestJni(); boolean flag = jni.init(); if(flag){ sum = jni.add(x, y); } tvSum.setText(String.valueOf(sum)); } }); }}
8.XML文件(activity_main.xml)
<LinearLayout 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:orientation="horizontal" > <EditText android:id="@+id/et_x" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" > </EditText> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" > </TextView> <EditText android:id="@+id/et_y" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" > </EditText> <Button android:id = "@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="=" /> <EditText android:id="@+id/et_sum" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" > </EditText></LinearLayout>
程序运行结果如图
总结一下JNI开发基本步骤
①编写.java类
②生成.class文件
③生成.h文件
③查阅.h文件
JNIEXPORT 和 JNICALL 是jni的宏
函数前的注释Signature: ()Ljava/lang/String;中的括号含义为:表示函数的参数为空,Ljava/lang/String表示函数的返回值是java的String对象
④编写.c/cpp文件
⑤创建 Android.mk文件(和.c文件同级目录)
⑥编译生成.so文件
NDK开发中的一些常见错误及解决办法
一、常见的几个错误及其解决办法
1. android.mk文件不存在
错误代码形如:
AndroidNDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
/cygdrive/h/heima6/jni2/ziliao/android-ndk-r7b/build/core/add-application.mk:133:* Android NDK: Aborting… 。 停止。
解决办法:
创建Android.mk文件。
2.android.mk文件的配置信息有错误
错误代码形如:
***Android NDK: Missing LOCAL_MODULE before including BUILD_SHARED_LIBRARY injni/Android.mk 。 停止。
解决办法:
修改Android.mk文件中的错误。有时候可能是一些看不见的特色字符导致,可以删除后重新建立一个。
3.c代码语法出现错误,编译不通过Error1.
错误代码形如:
make:* [obj/local/armeabi/objs/Hello/Hello.o]Error 1
解决办法:
检查C程序代码
4.java层c代码库没有找到
错误代码形如:
Causedby: java.lang.UnsatisfiedLinkError:Library Hell0 not found静态加载代码库的时候代码库没有找到.(调用库时出错)
解决办法:
检查库库的名字,看是否写错了。看
5.c代码函数签名出现错误(函数名出错)
错误代码形如:
Causedby: java.lang.UnsatisfiedLinkError: hello_from_c
解决办法:
C代码中函数名不合特定规范,改过来就行了。
- 其他隐含错误
如:在C代码中视图去访问已经释放了的内存空间。
- android下NDK开发环境搭建及TestJNI入门实例完整过程
- Eclipse下搭建NDK开发环境及入门Demo
- linux下android开发环境搭建及NDK安装(转)
- linux下android开发环境搭建及NDK安装(转)
- linux下android开发环境搭建及NDK安装
- linux下android开发环境搭建及NDK安装(转)
- Android NDK环境搭建和开发实例
- Android NDK环境搭建和开发入门
- Android NDK 入门之开发环境搭建
- Android NDK开发环境搭建及案例
- Android 及 NDK开发环境搭建
- Android Studio环境下ndk开发实例
- Ubuntu下搭建Android NDK开发环境
- windows 下搭建android NDK开发环境
- Ubuntu下搭建android NDK开发环境
- windows 下搭建android NDK开发环境
- linux下搭建android NDK开发环境
- Ubuntu 下 Android NDK 开发环境搭建
- Unity调用android
- 建造者模式的简写方式分析
- github上传时出现error: src refspec master does not match any解决办法
- C++中public,protected,private访问
- 使用Abator自动生成ibatis的DAO.Model.mapper.xml方法使用说明
- android下NDK开发环境搭建及TestJNI入门实例完整过程
- TCP netstat -az含义
- express的app.use两种方式:
- 收藏
- Java并发编程:深入剖析ThreadLocal
- php防止刷新页面重复提交
- 【HDU】 1973 Prime Path
- Maven生成可以直接运行的jar包的多种方式
- 利用Digester和JABX实现xml和bean之间的转换之对比(三)