普通的苦逼文艺程序猿  
——自强不息 厚德载物
  • 折腾目标

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"
#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的编写方法,看官方文档最有用

posted on 2014-01-19 18:29  Magic Cpatain  阅读(197)  评论(0)    收藏  举报