如何用jni开发android应用

2024-05-13

1. 如何用jni开发android应用

  JNI是Java NativeInterface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

  JNI的作用是让你在利用强大android平台的同时,使你仍然可以用其他语言例如C和C++等写程序。 作为JavaVM的一部分,JNI是一套双向的接口,允许Java与本地代码间的互相操作。

  JNI在交互中的角色

  1.JNI编程的一般步骤

  l  创建一个类(HelloWorld.java)

  HelloWorld.java

  class HelloWorld{

  private native void print();

  public static void main(String[] args) {

  newHelloWorld().print();

  }

  static {

  System.loadLibrary("HelloWorld");

  }

  }

  HelloWrold类首先声明了一个private nativeprint方法. static那几行是本地库。在Java代码中声明本地方法必须有"native"标识符,native修饰的方法,在Java代码中只作为声明存在。在 调用本地方法前,必须首先装载含有该方法的本地库. 如HelloWorld.java中所示,置于static块中,在Java VM初始化一个类时,首先执行这部分代码,这可保证调用本地方法前,装载了本地库。

  l  编译该类生成class文件

  用eclipse自动编译成class文件或用命令行javac HelloWorld.java来编译

  l  利用javah -jni产生头文件

  javah -jniHelloWorld

  "-jni"为默认参数,可有可无。上述命令会生成HelloWorld.h文件。

  l  用本地代码实现头文件中定义的方法

  必须根据javah生成的本地函数声明实现函数,如下:

  #include

  #include

  #include"HelloWorld.h"

  JNIEXPORTvoid JNICALL

  Java_HelloWorld_print(JNIEnv*env, jobject obj)

  {

  printf("Hello World!\n");

  return;

  }

  "jni.h"文件必须被包含,该文件定义了JNI所有的函数声明和数据类型。HelloWorld.h是上一步我们用javah生成的头文件

  l  运行

  最后用NDK编译你的本地代码并生成动态链接库.so文件。请注意,生成的本地库的名字,必须与System.loadLibrary("HelloWorld");待装载库的名字相同。

  然后在eclipse当中重新编译一遍android程 序。这里注意,你每一个改动本地代码并重新生成库都要手动的编译一遍android程序或修改eclipse的java代码使其自动重新生成程序,因为你 只修改本地代码eclipse会认为你的程序没有任何修改是不会自动编译的。

如何用jni开发android应用

2. 如何在Android下使用JNI

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

  2.环境配置

  2.1.安装jdk1.6
  (1)从jdk官方网站下载jdk-6u29-linux-i586.bin文件。
  (2)执行jdk安装文件
  [html] view plaincopyprint?
  01.$chmod a+x jdk-6u29-linux-i586.bin
  02.$jdk-6u29-linux-i586.bin
  $chmod a+x jdk-6u29-linux-i586.bin
  $jdk-6u29-linux-i586.bin
  (3)配置jdk环境变量

  [html] view plaincopyprint?
  01.$sudo vim /etc/profile
  02.#JAVAEVIRENMENT
  03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
  04.exportJRE_HOME=$JAVA_HOME/jre
  05.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
  06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
  $sudo vim /etc/profile
  #JAVAEVIRENMENT
  exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
  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?
  01.$java -version
  02.javaversion "1.6.0_29"
  03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
  04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)
  05.$javah
  06.用法:javah[选项]
  07.其中[选项]包括:
  08.-help输出此帮助消息并退出
  09.-classpath用于装入类的路径
  10.-bootclasspath用于装入引导类的路径
  11.-d输出目录
  12.-o输出文件(只能使用-d或-o中的一个)
  13.-jni生成JNI样式的头文件(默认)
  14.-version输出版本信息
  15.-verbose启用详细输出
  16.-force始终写入输出文件
  17.使用全限定名称指定(例
  18.如,java.lang.Object)。
  $java -version
  javaversion "1.6.0_29"
  Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
  JavaHotSpot(TM) Server VM (build 20.4-b02, 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?
  01.$sudo vim /etc/profile
  02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH
  03. 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官网下载ndk,目前最新版本为android-ndk-r6b-linux-x86.tar.bz2.
  (2)解压ndk到工作目录:
  [plain] view plaincopyprint?
  01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2
  02.$sudo mv android-ndk-r6b /usr/local/ndk
  $tar -xvf android-ndk-r6b-linux-x86.tar.bz2
  $sudo mv android-ndk-r6b /usr/local/ndk
  (3)设置ndk环境变量

  [plain] view plaincopyprint?
  01.$sudo vim /etc/profile
  02.exportPATH=/usr/local/ndk:$PATH
  $sudo vim /etc/profile
  exportPATH=/usr/local/ndk:$PATH

  编辑完毕后保存退出,并重启生效

  (4)验证安装

  [plain] view plaincopyprint?
  01.$ cd/usr/local/ndk/samples/hello-jni/
  02.$ ndk-build
  03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
  04.Gdbsetup : libs/armeabi/gdb.setup
  05.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文件如下:

  [html] view plaincopyprint?
  01.
  02.
  03.HelloWorld, JNITestActivity!
  04.JNITest
  05.Show
  06.
  
  
  HelloWorld, JNITestActivity!
  JNITest
  Show
  

  编辑res/layout/main.xml文件如下:

  [html] view plaincopyprint?
  01.
  02.<LinearLayoutxmlns:androidLinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  03.android:layout_width="fill_parent"
  04.android:layout_height="fill_parent"
  05.android:orientation="vertical">
  06.<TextView
  07.android:layout_width="fill_parent"
  08.android:layout_height="wrap_content"
  09.android:text="@string/hello"/>
  10.<EditText
  11.android:id="@+id/ed_name"
  12.android:layout_width="match_parent"
  13.android:layout_height="wrap_content"
  14.android:layout_gravity="center_horizontal"
  15.android:layout_marginLeft="5dp"
  16.android:layout_marginRight="5dp"/>
  17.<Button
  18.android:id="@+id/btn_show"
  19.android:layout_width="109dp"
  20.android:layout_height="wrap_content"
  21.android:layout_gravity="center_horizontal"
  22.android:text="@string/btn_show"/>
  23.
  
  <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical">
  <TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/hello"/>
  <EditText
  android:id="@+id/ed_name"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:layout_marginLeft="5dp"
  android:layout_marginRight="5dp"/>
  <Button
  android:id="@+id/btn_show"
  android:layout_width="109dp"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:text="@string/btn_show"/>
  

  我们在主界面上添加了一个EditText控件和一个Button控件。

  (3)编辑JNITest.java文件

  [java] view plaincopyprint?
  01.packageorg.tonny.jni;
  02.
  03.importandroid.app.Activity;
  04.importandroid.os.Bundle;
  05.importandroid.view.View;
  06.importandroid.widget.EditText;
  07.importandroid.widget.Button;
  08.
  09.
  10.publicclassJNITestextendsActivity {
  11.static{
  12.System.loadLibrary("JNITest");
  13.}
  14.privatenativeString GetReply();
  15.privateEditTextedtName;
  16.privateButtonbtnShow;
  17.Stringreply;
  18./**Called when the activity is first created. */
  19.@Override
  20.publicvoidonCreate(Bundle savedInstanceState) {
  21.super.onCreate(savedInstanceState);
  22.setContentView(R.layout.main);
  23.reply= GetReply();
  24.edtName= (EditText)this.findViewById(R.id.ed_name);
  25.btnShow= (Button)this.findViewById(R.id.btn_show);
  26.btnShow.setOnClickListener(newButton.OnClickListener() {
  27.publicvoidonClick(View arg0) {
  28.edtName.setText(reply);
  29.}
  30.});
  31.}
  32.}
  packageorg.tonny.jni;

  importandroid.app.Activity;
  importandroid.os.Bundle;
  importandroid.view.View;
  importandroid.widget.EditText;
  importandroid.widget.Button;

  publicclassJNITestextendsActivity {
  static{
  System.loadLibrary("JNITest");
  }
  privatenativeString GetReply();
  privateEditTextedtName;
  privateButtonbtnShow;
  Stringreply;
  /**Called when the activity is first created. */
  @Override
  publicvoidonCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  reply= GetReply();
  edtName= (EditText)this.findViewById(R.id.ed_name);
  btnShow= (Button)this.findViewById(R.id.btn_show);
  btnShow.setOnClickListener(newButton.OnClickListener() {
  publicvoidonClick(View arg0) {
  edtName.setText(reply);
  }
  });
  }
  }

  我们看这一段代码:

  [java] view plaincopyprint?
  01.static{
  02.System.loadLibrary("JNITest");
  03.}
  static{
  System.loadLibrary("JNITest");
  }

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

  再看这一段:

  [java] view plaincopyprint?
  01.privatenativeString GetReply();
  privatenativeString GetReply();
  native表示这个方法由本地代码定义,需要通过jni接口调用本地c/c++代码。

  [java] view plaincopyprint?
  01.publicvoidonClick(View arg0) {
  02.edtName.setText(reply);
  03.}
  publicvoidonClick(View arg0) {
  edtName.setText(reply);
  }

  这段代码表示点击按钮后,把native方法的返回的字符串显示到EditText控件。

  (4)编译工程,生成.class文件。

3. 如何在Android下使用JNI

关于如何在Android使用JNI调用C/C++代码库,网上已经有很多优秀的文章了,这里说一个大概过程吧:

首先需要懂C,其次要明白JNI的开发流程,然后还要知道NDK如何使用

1、在java代码中声明了一个native本地方法

Public native String helloFromc();

2、在项目目录中创建JNI文件夹

3、在JNI文件夹里面创建C文件,按照规范写代码

Jstring
Java_com_cheng_jnitest_MainActivity_helloFromc(JNIEnv* env,jobject obj)

4、用ndk-build指令编译
编译前需要配置Android.mk文件
//指定编译的文件夹,指定当前的目录
LOCAL_PATH := $(call my-dir)

//编译器在编译的时候会产生很多临时变量,中间变量最好在编译前清空所有的临时变量

include $(CLEAR_VARS)

//编译完成后的模块名
LOCAL_MOUDLE := hello
//编译的源文件

LOCAL_SRC_FILES:=hello.c

//编译一个动态库

//动态库.so 只包含运行的函数,不包含依赖,所以体积小,运行的时候回去系统寻找依赖

//静态库.a 包含所有的函数和运行的依赖,所以体积大,包含所有的api

include $(BUILD_SHARED_LIBRARY)

5、生成了一个so动态库,放到了libs里面

6、项目中引入依赖库

Static{

System.loadLibrary("hello");

}
-

如何在Android下使用JNI

4. 如何在Android下使用JNI

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。

NDK编译步骤:
1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。
2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )
4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。

5. 如何在Android下使用JNI

关于如何在Android使用JNI调用C/C++代码库,网上已经有很多优秀的文章了,这里说一个大概过程吧:

首先需要懂C,其次要明白JNI的开发流程,然后还要知道NDK如何使用

1、在java代码中声明了一个native本地方法

Public native String helloFromc();

2、在项目目录中创建JNI文件夹

3、在JNI文件夹里面创建C文件,按照规范写代码

Jstring
Java_com_cheng_jnitest_MainActivity_helloFromc(JNIEnv* env,jobject obj)

4、用ndk-build指令编译
编译前需要配置Android.mk文件
//指定编译的文件夹,指定当前的目录
LOCAL_PATH := $(call my-dir)

//编译器在编译的时候会产生很多临时变量,中间变量最好在编译前清空所有的临时变量

include $(CLEAR_VARS)

//编译完成后的模块名
LOCAL_MOUDLE := hello
//编译的源文件

LOCAL_SRC_FILES:=hello.c

//编译一个动态库

//动态库.so 只包含运行的函数,不包含依赖,所以体积小,运行的时候回去系统寻找依赖

//静态库.a 包含所有的函数和运行的依赖,所以体积大,包含所有的api

include $(BUILD_SHARED_LIBRARY)

5、生成了一个so动态库,放到了libs里面

6、项目中引入依赖库

Static{

System.loadLibrary("hello");

}

如何在Android下使用JNI

6. 如何在Android下使用JNI

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。

NDK编译步骤:
1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。
2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )
4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。

7. 如何在Android下使用JNI

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。
NDK编译步骤:
1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。
2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )
4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。

如何在Android下使用JNI

8. 如何在Android下使用JNI

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。
NDK编译步骤:
1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。
2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )
4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。