皮皮网
皮皮网

【微信源码解读】【event 源码】【源码翻红】hello jni源码

来源:古典网站asp源码 发表时间:2024-11-28 00:43:11

1.如何在Android下使用JNI
2.如何安装android ndk

hello jni源码

如何在Android下使用JNI

       ã€€ã€€1.引言

       ã€€ã€€æˆ‘们知道,Android系统的底层库由c/c++编写,上层Android应用程序通过Java虚拟机调用底层接口,衔接底层c/c++库与Java应用程序间的接口正是JNI(JavaNative Interface)。本文描述了如何在ubuntu下配置AndroidJNI的开发环境,以及如何编写一个简单的c函数库和JNI接口,并通过编写Java程序调用这些接口,最终运行在模拟器上的过程。

       ã€€ã€€2.环境配置

       ã€€ã€€2.1.安装jdk1.6

       ã€€ã€€ï¼ˆ1)从jdk官方网站下载jdk-6u-linux-i.bin文件。

       ã€€ã€€ï¼ˆ2)执行jdk安装文件

       ã€€ã€€[html] view plaincopyprint?源码微信源码解读

       ã€€ã€€.$chmod a+x jdk-6u-linux-i.bin

       ã€€ã€€.$jdk-6u-linux-i.bin

       ã€€ã€€$chmod a+x jdk-6u-linux-i.bin

       ã€€ã€€$jdk-6u-linux-i.bin

       ã€€ã€€(3)配置jdk环境变量

       ã€€ã€€[html] view plaincopyprint?

       ã€€ã€€.$sudo vim /etc/profile

       ã€€ã€€.#JAVAEVIRENMENT

       ã€€ã€€.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_

       ã€€ã€€.exportJRE_HOME=$JAVA_HOME/jre

       ã€€ã€€.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

       ã€€ã€€.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

       ã€€ã€€$sudo vim /etc/profile

       ã€€ã€€#JAVAEVIRENMENT

       ã€€ã€€exportJAVA_HOME=/usr/lib/java/jdk1.6.0_

       ã€€ã€€exportJRE_HOME=$JAVA_HOME/jre

       ã€€ã€€exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

       ã€€ã€€exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

       ã€€ã€€ä¿å­˜åŽé€€å‡ºç¼–辑,并重启系统。

       ã€€ã€€ï¼ˆ4)验证安装

       ã€€ã€€[html] view plaincopyprint?

       ã€€ã€€.$java -version

       ã€€ã€€.javaversion "1.6.0_"

       ã€€ã€€.Java(TM)SE Runtime Environment (build 1.6.0_-b)

       ã€€ã€€.JavaHotSpot(TM) Server VM (build .4-b, mixed mode)

       ã€€ã€€.$javah

       ã€€ã€€.用法:javah[选项]<ç±»>

       ã€€ã€€.其中[选项]包括:

       ã€€ã€€.-help输出此帮助消息并退出

       ã€€ã€€.-classpath<路径>用于装入类的路径

       ã€€ã€€.-bootclasspath<路径>用于装入引导类的路径

       ã€€ã€€.-d<目录>输出目录

       ã€€ã€€.-o<文件>输出文件(只能使用-d或-o中的一个)

       ã€€ã€€.-jni生成JNI样式的头文件(默认)

       ã€€ã€€.-version输出版本信息

       ã€€ã€€.-verbose启用详细输出

       ã€€ã€€.-force始终写入输出文件

       ã€€ã€€.使用全限定名称指定<ç±»>(例

       ã€€ã€€.如,java.lang.Object)。

       ã€€ã€€$java -version

       ã€€ã€€javaversion "1.6.0_"

       ã€€ã€€Java(TM)SE Runtime Environment (build 1.6.0_-b)

       ã€€ã€€JavaHotSpot(TM) Server VM (build .4-b, mixed mode)

       ã€€ã€€$javah

       ã€€ã€€ç”¨æ³•ï¼šjavah[选项]<ç±»>

       ã€€ã€€å…¶ä¸­[选项]包括:

       ã€€ã€€-help输出此帮助消息并退出

       ã€€ã€€-classpath<路径>用于装入类的路径

       ã€€ã€€-bootclasspath<路径>用于装入引导类的路径

       ã€€ã€€-d<目录>输出目录

       ã€€ã€€-o<文件>输出文件(只能使用-d或-o中的一个)

       ã€€ã€€-jni生成JNI样式的头文件(默认)

       ã€€ã€€-version输出版本信息

       ã€€ã€€-verbose启用详细输出

       ã€€ã€€-force始终写入输出文件

       ã€€ã€€ä½¿ç”¨å…¨é™å®šåç§°æŒ‡å®š<ç±»>(例

       ã€€ã€€å¦‚,java.lang.Object)。2.2.安装android应用程序开发环境

       ã€€ã€€ubuntu下安装android应用程序开发环境与windows类似,依次安装好以下软件即可:

       ã€€ã€€ï¼ˆ1)Eclipse

       ã€€ã€€ï¼ˆ2)ADT

       ã€€ã€€ï¼ˆ3)AndroidSDK

       ã€€ã€€ä¸Žwindows下安装唯一不同的一点是,下载这些软件的时候要下载Linux版本的安装包。

       ã€€ã€€å®‰è£…好以上android应用程序的开发环境后,还可以选择是否需要配置emulator和adb工具的环境变量,以方便在进行JNI开发的时候使用。配置步骤如下:

       ã€€ã€€æŠŠemulator所在目录android-sdk-linux/tools以及adb所在目录android-sdk-linux/platform-tools添加到环境变量中,android-sdk-linux指androidsdk安装包android-sdk_rxx-linux的解压目录。

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$sudo vim /etc/profile

       ã€€ã€€.exportPATH=~/software/android/android-sdk-linux/tools:$PATH

       ã€€ã€€. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

       ã€€ã€€$sudo vim /etc/profile

       ã€€ã€€exportPATH=~/software/android/android-sdk-linux/tools:$PATH

       ã€€ã€€exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

       ã€€ã€€ç¼–辑完毕后退出,并重启生效。

       ã€€ã€€2.3.安装NDK

       ã€€ã€€NDK是由android提供的编译android本地代码的一个工具。

       ã€€ã€€ï¼ˆ1)从androidndk官网/sdk/ndk/index.html下载ndk,目前最新版本为android-ndk-r6b-linux-x.tar.bz2.

       ã€€ã€€ï¼ˆ2)解压ndk到工作目录:

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$tar -xvf android-ndk-r6b-linux-x.tar.bz2

       ã€€ã€€.$sudo mv android-ndk-r6b /usr/local/ndk

       ã€€ã€€$tar -xvf android-ndk-r6b-linux-x.tar.bz2

       ã€€ã€€$sudo mv android-ndk-r6b /usr/local/ndk

       ã€€ã€€ï¼ˆ3)设置ndk环境变量

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$sudo vim /etc/profile

       ã€€ã€€.exportPATH=/usr/local/ndk:$PATH

       ã€€ã€€$sudo vim /etc/profile

       ã€€ã€€exportPATH=/usr/local/ndk:$PATH

       ã€€ã€€ç¼–辑完毕后保存退出,并重启生效

       ã€€ã€€ï¼ˆ4)验证安装

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$ cd/usr/local/ndk/samples/hello-jni/

       ã€€ã€€.$ ndk-build

       ã€€ã€€.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

       ã€€ã€€.Gdbsetup : libs/armeabi/gdb.setup

       ã€€ã€€.Install : libhello-jni.so => libs/armeabi/libhello-jni.so

       ã€€ã€€$ cd/usr/local/ndk/samples/hello-jni/

       ã€€ã€€$ ndk-build

       ã€€ã€€Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

       ã€€ã€€Gdbsetup : libs/armeabi/gdb.setup

       ã€€ã€€Install : libhello-jni.so => libs/armeabi/libhello-jni.so

       ã€€ã€€3.JNI实现

       ã€€ã€€æˆ‘们需要定义一个符合JNI接口规范的c/c++接口,这个接口不用太复杂,例如输出一个字符串。接下来,则需要把c/c++接口的代码文件编译成共享库(动态库).so文件,并放到模拟器的相关目录下。最后,启动Java应用程序,就可以看到最终效果了。

       ã€€ã€€3.1.编写Java应用程序代码

       ã€€ã€€ï¼ˆ1)启动Eclipse,新建android工程

       ã€€ã€€Project:JNITest

       ã€€ã€€Package:org.tonny.jni

       ã€€ã€€Activity:JNITest

       ã€€ã€€ï¼ˆ2)编辑资源文件

       ã€€ã€€ç¼–辑res/values/strings.xml文件如下:

       ã€€ã€€

       ã€€ã€€ç¼–辑res/layout/main.xml文件

       ã€€ã€€æˆ‘们在主界面上添加了一个EditText控件和一个Button控件。

       ã€€ã€€ï¼ˆ3)编辑JNITest.java文件

       ã€€

       ã€€ã€€static表示在系统第一次加载类的时候,先执行这一段代码,在这里表示加载动态库libJNITest.so文件。

       ã€€ã€€å†çœ‹è¿™ä¸€æ®µï¼š

       ã€€ã€€[java] view plaincopyprint?

       ã€€ã€€.privatenativeString GetReply();

       ã€€ã€€privatenativeString GetReply();

       ã€€ã€€native表示这个方法由本地代码定义,需要通过jni接口调用本地c/c++代码。

       ã€€ã€€[java] view plaincopyprint?

       ã€€ã€€.publicvoidonClick(View arg0) {

       ã€€ã€€.edtName.setText(reply);

       ã€€ã€€.}

       ã€€ã€€publicvoidonClick(View arg0) {

       ã€€ã€€edtName.setText(reply);

       ã€€ã€€}

       ã€€ã€€è¿™æ®µä»£ç è¡¨ç¤ºç‚¹å‡»æŒ‰é’®åŽï¼ŒæŠŠnative方法的返回的字符串显示到EditText控件。

       ã€€ã€€ï¼ˆ4)编译工程,生成.class文件。

       ã€€ã€€3.2.用javah工具生成符合JNI规范的c语言头文件

       ã€€ã€€åœ¨ç»ˆç«¯ä¸­ï¼Œè¿›å…¥android工程所在的bin目录

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$cd ~/project/Android/JNITest/bin

       ã€€ã€€$cd ~/project/Android/JNITest/bin

       ã€€ã€€æˆ‘们用ls命令查看,可以看到bin目录下有个classes目录,其目录结构为classes/org/tonny/jni,即classes的子目录结构是android工程的包名org.tonny.jni。请注意,下面我们准备执行javah命令的时候,必须进入到org/tonny/jni的上级目录,即classes目录,否则javah会提示找不到相关的java类。

       ã€€ã€€ä¸‹é¢ç»§ç»­ï¼š

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$cd classes

       ã€€ã€€.$javah org.tonny.jni.JNITest

       ã€€ã€€.$ls

       ã€€ã€€.org org_tonny_jni_JNITest.h

       ã€€ã€€$cd classes

       ã€€ã€€$javah org.tonny.jni.JNITest

       ã€€ã€€$ls

       ã€€ã€€org org_tonny_jni_JNITest.h

       ã€€ã€€æ‰§è¡Œjavahorg.tonny.jni.JNITest命令,在classes目录下会生成org_tonny_jni_JNITest.h头文件。如果不进入到classes目录下的话,也可以这样:

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

       ã€€ã€€$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

       ã€€ã€€-classpath 参数表示装载类的目录。

       ã€€ã€€3.3.编写c/c++代码

       ã€€ã€€ç”Ÿæˆorg_tonny_jni_JNITest.h头文件后,我们就可以编写相应的函数代码了。下面在android工程目录下新建jni目录,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h头文件拷贝到jni目录下,并在jni目录下新建org_tonny_jni_JNITest.c文件,编辑代码如下:

       ã€€ã€€[cpp] view plaincopyprint?

       ã€€ã€€.#include<jni.h>

       ã€€ã€€.#include<string.h>

       ã€€ã€€.#include"org_tonny_jni_JNITest.h"

       ã€€ã€€.

       ã€€ã€€.

       ã€€ã€€.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

       ã€€ã€€.(JNIEnv *env, jobject obj){

       ã€€ã€€.return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");

       ã€€ã€€.}

       ã€€ã€€#include<jni.h>

       ã€€ã€€#include<string.h>

       ã€€ã€€#include"org_tonny_jni_JNITest.h"

       ã€€ã€€JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

       ã€€ã€€(JNIEnv *env, jobject obj){

       ã€€ã€€return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");

       ã€€ã€€}

       ã€€ã€€æˆ‘们可以看到,该函数的实现相当简单,返回一个字符串为:"Hello,JNITest"

       ã€€ã€€3.4.编写Android.mk文件

       ã€€ã€€åœ¨~/project/Android/JNITest/jni目录下新建Android.mk文件,android可以根据这个文件的编译参数编译模块。编辑Android.mk文件如下:

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.LOCAL_PATH:= $(call my-dir)

       ã€€ã€€.include$(CLEAR_VARS)

       ã€€ã€€.LOCAL_MODULE := libJNITest

       ã€€ã€€.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

       ã€€ã€€.include$(BUILD_SHARED_LIBRARY)

       ã€€ã€€LOCAL_PATH:= $(call my-dir)

       ã€€ã€€include$(CLEAR_VARS)

       ã€€ã€€LOCAL_MODULE := libJNITest

       ã€€ã€€LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

       ã€€ã€€include$(BUILD_SHARED_LIBRARY)

       ã€€ã€€LOCAL_MODULE表示编译的动态库名称

       ã€€ã€€LOCAL_SRC_FILES 表示源代码文件

       ã€€ã€€3.5.用ndk工具编译并生成.so文件

       ã€€ã€€è¿›å…¥åˆ°JNITest的工程目录,执行ndk-build命令即可生成libJNITest.so文件。

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$cd ~/project/Android/JNITest/

       ã€€ã€€.$ndk-build

       ã€€ã€€.Invalidattribute name:

       ã€€ã€€.package

       ã€€ã€€.Install : libJNITest.so => libs/armeabi/libJNITest.so

       ã€€ã€€$cd ~/project/Android/JNITest/

       ã€€ã€€$ndk-build

       ã€€ã€€Invalidattribute name:

       ã€€ã€€package

       ã€€ã€€Install : libJNITest.so => libs/armeabi/libJNITest.so

       ã€€ã€€å¯ä»¥çœ‹åˆ°ï¼Œåœ¨å·¥ç¨‹ç›®å½•çš„libs/armeabi目录下生成了libJNITest.so文件。

       ã€€ã€€3.6.在模拟器上运行

       ã€€ã€€ï¼ˆ1)首先,我们把android模拟器启动起来。进入到emulator所在目录,执行emulator命令:

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$cd ~/software/android/android-sdk-linux/tools

       ã€€ã€€.$./emulator @AVD-2.3.3-V -partition-size

       ã€€ã€€$cd ~/software/android/android-sdk-linux/tools

       ã€€ã€€$./emulator @AVD-2.3.3-V -partition-size

       ã€€ã€€AVD-2.3.3-V表示你的模拟器名称,与在Eclipse->AVDManager下的AVDName对应,-partition-size表示模拟器的存储设备容量。

       ã€€ã€€ï¼ˆ2)接下来,我们需要把libJNITest.so文件拷贝到模拟器的/system/lib目录下,执行以下命令:

       ã€€ã€€[plain] view plaincopyprint?

       ã€€ã€€.$cd ~/project/Android/JNITest/libs/armeabi/

       ã€€ã€€.$adb remount

       ã€€ã€€.$adb push libJNITest.so /system/lib

       ã€€ã€€. KB/s ( bytes in 0.s)

       ã€€ã€€$cd ~/project/Android/JNITest/libs/armeabi/

       ã€€ã€€$adb remount

       ã€€ã€€$adb push libJNITest.so /system/lib

       ã€€ã€€ KB/s ( bytes in 0.s)

       ã€€ã€€å½“在终端上看到有 KB/s ( bytes in 0.s)传输速度等信息的时候,说明拷贝成功。

       ã€€ã€€ï¼ˆ3)在终端上执行JNITest程序,这个我们可以在Eclipse下,右键点击JNITest工程,RunAs->Android Application,即可在模拟器上启动程序

如何安装android ndk

       ä¸‹è½½å®ŒæˆåŽè¿›è¡Œè§£åŽ‹ï¼Œå°±å¯ä»¥ç›´æŽ¥ä½¿ç”¨ç›®å½•ä¸­çš„ndk-build了。为了使用方便,可以用如下命令将ndk-build放入默认路径中:

       [plain] view plain copy

       export PATH=$PATH:<你解压好的目录地址>

       NDK的使用方法

       ç›®å‰ä¸ºæ­¢ï¼Œç”¨C/C++编写Android应用程序有两种方式:

       1. 用C/C++编写主要的逻辑层,再用java编写界面层并调用C/C++的库;

       2. 用C/C++直接开发完整的应用程序,完全不用java。(仅Android 2.3之后的版本支持)

       ç¬¬ä¸€ç§æ–¹æ³•è¾ƒä¸ºé€šç”¨ï¼Œå› ä¸ºç”¨java开发Android应用程序的界面比较简单;第二种方法较为复杂并且很少用到。在此我们只介绍第一种使用方法的步骤,第二种使用方法可以在第一种方法的基础上,参照NDK目录中自带的例子程序samples/native-activity。

       æˆ‘们以一个简单的例子,一步步带领大家写出一个简单的hello-jni程序。

       ç¬¬ä¸€æ­¥ 建立一个Android工程

       å¦‚果你使用eclipse进行开发,很简单,在此就不赘述了。不过为了与下文的名称保持一致,请把项目名设为hello-jni,包名为com.example.hellojni,类名为HelloJni。

       å¦‚果你使用shell进行开发,执行如下三行命令即可:

       [plain] view plain copy

       mkdir hello-jni

       cd hello-jni

       android create project -p . -t android-8 -k com.example.hellojni -a HelloJni

       ç¬¬äºŒæ­¥ 编写C源文件及Makefile

       åœ¨é¡¹ç›®ç›®å½•ä¸‹æ–°å»ºä¸€ä¸ªjni目录,然后在jni目录下建立两个文件:

       ç¬¬ä¸€ä¸ªï¼šmain.c文件,内容如下:

       [cpp] view plain copy

       #include <string.h>

       #include <jni.h>

       /* This is a trivial JNI example where we use a native method

        * to return a new VM String. See the corresponding Java source

        * file located at:

        *

        * hello-jni/src/com/example/HelloJni/HelloJni.java

        */

       jstring

       Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,

        jobject thiz )

       {

        return (*env)->NewStringUTF(env, "Hello from JNI !");

       }

       ç¬¬äºŒä¸ªï¼šAndroid.mk文件,内容如下:

       [cpp] view plain copy

       LOCAL_PATH := $(call my-dir)

       include $(CLEAR_VARS)

       LOCAL_MODULE := hello-jni

       LOCAL_SRC_FILES := hello-jni.c

       include $(BUILD_SHARED_LIBRARY)

       ç¬¬ä¸‰æ­¥ 编译C源码生成so文件

       ç›´æŽ¥åœ¨hello-jni目录下执行ndk-build。如果编译成功,可以看到生成了libs/armeabi/libhello-jni.so文件,该文件就是我们得到的C库了。

相关栏目:知识

.重点关注