Android第一个NDK示例

前面我们讲了三种方式编译原生程序,今天我们讲一下android代码中编译原生程序的例子。这个例子是基于上篇文章eclipse编译那个例子,因此没看过的同学,可以转战这里了:http://blog.csdn.net/u012195899/article/details/52704206

现在,我们开始修改这个hello3工程。

1、首先在com.example.hello3目录下新建类JNI.java,这个类就是我们调用.so库中方法的接口,我们只提供一个方法getString(),示例代码如下:

package com.example.hello3;

public class JNI {
	public native String getString();
}
2、修改 MainActivity类如下:

package com.example.hello3;

import android.app.Activity;
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.Toast;

public class MainActivity extends Activity {
	
	static{
		System.loadLibrary("hello_jni");
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final JNI jni = new JNI();
		Button btn = (Button)findViewById(R.id.button);
		
		btn.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				Toast.makeText(getApplicationContext(), jni.getString(), 1500).show();
			}
				
			});
		
		
	}

	
}
MainActivity说明:首先加载hello_jni库文件,这里需要注意lib\armeabi目录下生成的是libhello_jni.so文件,我们在代码中写加载库名的时候省略前缀lib和后缀.so。在onCreate()方法中,我们可以看到它的逻辑是首先加载布局文件,然后监控button空间的点击事件,一旦点击,就调用JNI中的getString方法并弹出。

3、修改activity_main.xml布局文件

<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="com.example.hello3.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <Button
		android:id="@+id/button"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:text="Button" />

</RelativeLayout>
布局文件说明:我们在这个文件中,只是添加了一个button控件而已,方便MainActivity中的测试。

4、修改jni文件中的hello.c文件

#include "com_example_hello3_JNI.h"

JNIEXPORT jstring JNICALL Java_com_example_hello3_JNI_getString(JNIEnv* env, jobject obj)
{
    //返回一个字符串
    return (*env)->NewStringUTF(env,"Hello NDK!");
}
hello.c文件说明:在这个文件中,我们引用了一个头文件“com_example_hello3_JNI.h”,头文件的格式是包名_类名,同时定义了一个方法名,方法名称为Java_工程包名_类名_方法名,方法内容为我们返回字符串“Hello NDK!”。这样的定义格式,就说明我们这个方法可以通过JNI对象调用。这个时候会看到引用了头文件,接下来我们就要生成这个头文件了。

5、生成.h头文件

通过前面的定义可以看到,本次工程中,只有JNI类中的方法实现定义在.so文件中,因此我们只需要生成该类的头文件即可。生成.h头文件的步骤为,打开命令行,进入你的eclipse空间目录,进入hello3工程下的src文件夹,执行命令:javah com.example.hello3.JNI


执行完后,我们可以看到,在src目录下生成了对应的头文件,将生成的头文件复制到hello3工程中jni目录下,使得hello.c文件可以引用到这个头文件。


6、最后,我们修改jni目录下的Android.mk文件,修改如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
LOCAL_MODULE := hello_jni
LOCAL_SRC_FILES := hello.c
include $(BUILD_SHARED_LIBRARY)
Android.mk文件说明:在这个文件中,我们修改了两处,第一处是第四行LOCAL_MODULE的名称,我们修改为hello_jni,因为在MainActivity中,我们加载的.so文件名称为hello_jni,第二处是最后一行,这一行指定了生成的文件类型,我们之前生成的是可执行文件,现在我们将其修改为BUILD_SHARED_LIBRARY表示生成动态库文件。
修改完成后,大家就可以看到在控制台下eclipse自动编译我们的.c文件为libhello_jni.so文件。


此时,我们整个项目终于构建完成。在虚拟机或者真机中运行hello3项目,点击按钮,可以看到弹出字符串,效果如下:

注意:在虚拟机中启动时控制台可能报错如下:Installation error: INSTALL_FAILED_NO_MATCHING_ABIS,这是系统架构不匹配的报错,因为我们在编译so库时定义了运行于arm之上,所以在启动虚拟机的时候,注意选择arm架构的虚拟机。真机中则不会存在这个问题。

到此,我们的第一个NDK例子讲述完毕。博主也是小菜鸟,整篇文章是自己参考非虫大大的书和其他博客自己动手做出来的,如果其中讲述有什么错误欢迎各位大大交流指正。


猜你喜欢

转载自blog.csdn.net/u012195899/article/details/52711524