- 折腾目标
1> elipse NDK 环境配置
2> 做个deamo 使用C++完成字符串相加和数字相加的功能,并显示在textview中
- 完成情况
全部完成
- 环境
eclipse(ADT+NDK) Linux mint 16
过程简介:
1> elipse NDK 环境配置
为android工程添加NDK支持

右键android项目
设置Eclipse 自动生成JNI头文件

、
workding Dirctory 设置成src 就是java文件的存放地址
参数设置:
-classpath : java 编译后的.class 文件路径
-bootclasspath:设置成android sdk android.jar 的路径,这个路径和你需要使用的SDK版本有关,如果不添加这项就会报找不到super class的错误
-d 生成头文件的输出目录
#{java_type_name}是当前需要生成头文件的类名
如果需要对不同的芯片类型进行支持,在编写C文件的时候添加宏
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__mips__)
#define ABI "mips"
#else
#define ABI "unknown"
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__mips__)
#define ABI "mips"
#else
#define ABI "unknown"
#endif
可以将这个宏写在一个头文件中, 比如“platform.h” 在所有需要编译的h文件中include这个头文件
也可以根据自己的机器或者虚拟机类型自行修改
创建 Application.mk

这样就可以在编译C代码的时候为各种不同的架构生成链接库了。
将编辑器切换到要生成头文件的java文件(必须包含static native 方法)下,使用刚才添加的JAVAH运行,就会在jni目录下生成头文件
用C语言实现头文件中的方法网上例子很多,可以自行查找(例如:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/14/2137854.html)
2> 做个deamo 使用C++完成字符串相加和数字相加的功能,并显示在textview中
在activity_main.xml中添加两个textview
<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/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <TextView android:id="@+id/textView2" android:layout_below="@id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
编写MainActivity.java
package com.sc.helloworld; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity { //调用我们生成的动态库,TestNdk依赖CPPNDK,所以这两个库都要调用,否则会出现链接异常(程序启动不了) static { System.loadLibrary("CPPNDK"); System.loadLibrary("TestNdk"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String addStr = AddStr("SS","AA"); int sumInt = addInit(10, 22); String sumStr = "10 + 22 = " + sumInt; TextView tv1 = (TextView)findViewById(R.id.textView1); TextView tv2 = (TextView)findViewById(R.id.textView2); tv1.setText(addStr); tv2.setText(sumStr); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //本地方法,使用JAVAH生成头文件之后,程序会自动匹配类型相同的C/C++函数, //遇见第一个相匹配的函数则不会继续匹配其他 static public native String AddStr(String strA, String strB); static public native int addInit(int a, int b); }
创建MyClass类
/* * MyClass.h * * Created on: 2014年1月19日 * Author: shaochen */ #ifndef MYCLASS_H_ #define MYCLASS_H_ #include "platform.h" #include <string> #include <jni.h> using namespace std; class MyClass { public: MyClass(); ~MyClass(); int addInt(int a, int b); string addString(string strA, string strB); /* * 将std::string 转换为jstring * */ jstring str2jstring(JNIEnv* env,const char* pat); /* * 将jstring转换为std::string * */ string jstring2str(JNIEnv* env, jstring jstr); }; #endif /* MYCLASS_H_ */
/* * MyClass.cpp * * Created on: 2014年1月19日 * Author: shaochen */ #include <MyClass.h> MyClass::MyClass() { // TODO Auto-generated constructor stub } MyClass::~MyClass() { // TODO Auto-generated destructor stub } int MyClass::addInt(int a, int b) { return a + b; } // string MyClass::addString(string strA, string strB) { return strA + strB; } jstring MyClass::str2jstring(JNIEnv* env, const char* pat) { //注意: //在 C 中,JNI 函数调用由“(*env)->”作前缀,目的是为了取出函数指针所引 //用的值。 //在 C++ 中,JNIEnv 类拥有处理函数指针查找的内联成员函数。 //C 语法: jsize len = (*env)->GetArrayLength(env,array); //C++语法: jsize len =env->GetArrayLength(array); return env->NewStringUTF(pat); } string MyClass::jstring2str(JNIEnv* env, jstring jstr) { const char* tempStr; tempStr = env->GetStringUTFChars(jstr, false); string str(tempStr); return str; }
创建TestNDK.cpp 用于实现JAVAH生成头文件的方法
#include <jni.h> #include "com_sc_helloworld_MainActivity.h" #include <stdlib.h> #include <stdio.h> #include "platform.h" #include "MyClass.h" //#include <string> using namespace std; #ifdef __cplusplus extern "C" { #endif /* * Class: com_sc_helloworld_MainActivity * Method: AddStr * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_sc_helloworld_MainActivity_AddStr (JNIEnv* env, jclass arg, jstring strA, jstring strB) { MyClass cl; string CStrA = cl.jstring2str(env, strA); string CStrB = cl.jstring2str(env, strB); string CsumStr = cl.addString(CStrA, CStrB); jstring sumStr = cl.str2jstring(env, CsumStr.c_str()); return sumStr; } /* * Class: com_sc_helloworld_MainActivity * Method: addInit * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_sc_helloworld_MainActivity_addInit (JNIEnv * env, jclass arg, jint a, jint b) { MyClass cl; return cl.addInt((int)a, (int)b); } #ifdef __cplusplus } #endif
添加完这些代码之后会发现eclipse无法识别C++标准库的头文件,解决办法:
http://cherishlc.iteye.com/blog/1758643
另外需要在Application.mk中添加APP_STL := stlport_static 来保证顺利编译stl代码
我的摄像是将MyClass单独编译成一个动态库,由TestNDK.so调用,Android.mk编辑如下
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := CPPNDK LOCAL_SRC_FILES := MyClass.cpp include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := TestNdk LOCAL_SHARED_LIBRARIES := CPPNDK LOCAL_SRC_FILES := TestNdk.cpp include $(BUILD_SHARED_LIBRARY)
注意使用
LOCAL_SHARED_LIBRARIES 来添加你要依赖的动态库
编辑完成之后按ctrl+B完成编译

运行结果:

下面要做的事情:
学习JNI,了解java和C++之间数据类型的转换
熟悉Android.mk的编写方法,看官方文档最有用

浙公网安备 33010602011771号