Android Jni基础学习


一直以来,都觉得Jni很神奇的一个东西,今天我就学习学习这个神奇的东西。

在给定的平台上采用java通过jni调用本地方法,而本地方法是以库文件的形式存放的,在windows平台上是DLL文件形式,在unix机器上是so文件形式。通过调用本地库的内部方法,使java可以实现和本地机器的紧密联系,调用系统级的各接口方法。


第一步:安装windows系统上安装与使用Android NDK

http://www.cnblogs.com/luxiaofeng54/archive/2011/02/12/1952391.html


第二步:

新建一个工程,可以建立一个普通的Java工程或者一个Android工程都可以。类似下面这样:

package com.example.ajnitest1;
 
import android.os.Bundle;
import android.app.Activity;
 
public class MainActivity extends Activity {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    public static native void Show();
    
}


你必须要写一个标示符为native的方法,并且没有方法体的。类似上面那样。


1. 生成.java文件:注意进入到src下MainActivity这个类所在的目录下:

javac MainActivity.java

然后在bin/classes目录下会生成一个MainActivity.java的类文件;

2. 生成.h文件:注意要进入到bin目录下的classes这个目录下,因为你有native方法的类生成的类文件在这个目录下:

javah com.example.ajnitest1.MainActivity

2013.5.6 补充:javah -classpath bin/classes -d jni com.example.jnitest1.MainActivity,这样的好处是可以直接在项目中生成jni目录,要不还要自己新建一个。

然后在bin/classes目录下会生成com_example_ajnitest1_MainActivity.h这个文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_ajnitest1_MainActivity */

#ifndef _Included_com_example_ajnitest1_MainActivity
#define _Included_com_example_ajnitest1_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_ajnitest1_MainActivity
 * Method:    Show
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_ajnitest1_MainActivity_Show
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

说实话,我看不太懂。看着似乎这个名称是:Java+包名+类名+方法名 -> Java_com_example_ajnitest1_MainActivity_Show


我从新编译了一个:这回native方法返回值是String,如下:

public native String pop();

编译后的.h文件如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_a2_MainActivity */

#ifndef _Included_com_example_a2_MainActivity
#define _Included_com_example_a2_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_a2_MainActivity
 * Method:    pop
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_a2_MainActivity_pop
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

对比一下注释中的内容,标明了方法的返回值的不同。


编写C文件,名称为:com_example_a2_MainActivity.c

#include <string.h>
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_example_a2_MainActivity_pop (JNIEnv * env, jobject obj){
  return (*env)->NewStringUTF(env, "songshichao");
}

编写Android.mk文件,名称就是Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := A2
LOCAL_SRC_FILES := com_example_a2_MainActivity.c

include $(BUILD_SHARED_LIBRARY)




OK,继续。。。

打开cygwin,不会安装的看这个帖子:http://www.cnblogs.com/luxiaofeng54/archive/2011/02/12/1952391.html

了解到它就是模拟个unix环境,以为命令都一样呢,想切换到d盘,怎么也进不去,啥命令都不好使,后来才知道,要这样用才行:cd /cygdrive/d,然后就可以自由的使用linux的命令了。

Administrator@PC-201204141932 ~
$ cd /cygdrive/d

然后进入到你的项目目录的jni目录下,去编译:

前几次总是出错,如下:

$ ndk-build
make: *** 没有规则可以创建“obj/local/armeabi/objs/A2/com.example_a2_MainActivity.o”需要的目标“jni/com.example_a2_MainActivity.c”。 停止。

后来仔细检查了下,确实我的Android.mk文件写错了,太大意了。

修改后从新build,正确了,结果如下:

$ ndk-build
Cygwin         : Generating dependency file converter script
Compile thumb  : A2 <= com_example_a2_MainActivity.c
SharedLibrary  : libA2.so
Install        : libA2.so => libs/armeabi/libA2.so


刷新libs文件夹后,发现,确实多了一个armeabi文件夹,里面有一个libA2.so文件,就不截图了。


继续,既然写了这个东西,就得用啊,怎么用呢,像这样:

package com.example.a2;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {
	// 库的扩展名字不用写出来,究竟是DLL还是SO,由系统自己判断。
	static {
		System.loadLibrary("A2");
	}

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Log.i("tag",  pop());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    
    public native String pop();
}


去Logcat上看,哈哈, 已经成功输出内容了,真不错,我纠结了好久了,终于基本的知道如何使用JNI了。

 

注意:

Jni的弊端:

1.使用了jni,那么这个java app 将不能跨平台,如果要移植到别的平台上,那么native代码就需要进行重新编写。

2.Java是强类型的语言,而C/C++不是,因此你写jni时要更小心。

 


参考链接:

1.下面这篇讲的和上面差不多,唯一的区别,我用的环境是cygwin,就是在windows环境下开发jni需要c/c++编译器的支持。他使用GNUStep,下载地址http://www.gnustep.org/experience/Windows.html。具体看链接。

android 之JNI开发步骤总结
http://www.eoeandroid.com/forum.php?mod=viewthread&tid=207213&fromuid=511991


2.这篇也喝上面的差不多,不过做了很多理论解释

cygwin+ndk+eclipse下JNI技术入门
http://www.eoeandroid.com/forum.php?mod=viewthread&tid=189315&fromuid=511991


3.这个是装一个插件可以不用命令行build,不过我没看太懂。

http://permadi.com/blog/2011/09/creating-your-first-android-jnindk-project-in-eclipse-with-sequoyah/

 

4.仍然是一篇基础的博客

http://www.cnblogs.com/skyseraph/archive/2012/03/20/2407593.html


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值