• 1、定义本地【native】方法。通常情况下,应单独定义一个类来封装所有native方法。native方法相当于一个【接口】中的方法,只有方法声明,没有方法体。
  • 2、在项目根目录下创建【jni文件夹】,将利用【javah】命令生成的【.h】头文件拷到jni目录中。然而在实际测试中发现,这个文件没有任何卵用,不拷贝也没问题。
  • 3、在jni目录中编写所需的【.c】文件,这一步才是核心,在c代码中,实现上面定义的本地方法。其中ndk工具中提供的<jni.h>头文件中详细定义了JNI【基本数据类型】和【本地等效类型】之间的转换。
  • 4、在jni目录中创建【Android.mk】文件,主要是声明所引用的.c文件和生成的.so库的文件名
  • 5、创建【Application.mk】文件,主要是声明所有支持的平台。每增加一个支持的架构,编译后就会在lib目录下生成一个相应架构平台的目录。
  • 6、使用【ndk】工具编译生成【.so动态链接库文件】。当完成这一步后,如果我们以后不需要再重新编译,我们就可以直接删除【jni】目录。另外发布的时候这些文件都是应该删掉的。
  • 7、使用时先 System.loadLibrary("hello"),然后直接调用本地native方法即可。注意,加载库文件时的文件名要去掉前面的lib和后面的.so

1、定义本地【native】方法

定义本地方法,通常情况下,应单独定义一个类来封装所有native方法
/** 存放native方法的类 */
public class MyNativeMethods {
    private static MyNativeMethods mEmployee;
    private MyNativeMethods() {
    }
    public static MyNativeMethods getInstance() {
        if (mEmployee == null) {
            mEmployee = new MyNativeMethods();
        }
        return mEmployee;
    }
    //相当于在java代码中定义了一个接口,然后用C语言实现了此接口
    public native String helloFromC();
    public native int passwordFromC(int x, int y);
}

2、利用javah命令生成的.h头文件

1、定位到工程的【 src目录】下
cd/d E:\HelloFromC\src

2、对native方法所在类执行【javah】命令,其中javah后面的类文件的格式是【包名.类名】
javah com.bqt.hellofromc.MyNativeMethods
执行过程如下:

报错的原因是因为MyNativeMethods中有中文字符,即使是注释也会报错,且发现一处中文就报错一次
但是这并不影响处理结果,所以大可不用理会

3、在项目根目录下创建【jni文件夹】,将生成的【.h文件】拷贝到jni目录下
在实际测试中发现,这个文件没有任何卵用,不拷贝也没问题。可能是因为我测试的代码比较简单吧。


文件的内容为
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_bqt_hellofromc_MyNativeMethods */
#ifndef _Included_com_bqt_hellofromc_MyNativeMethods
#define _Included_com_bqt_hellofromc_MyNativeMethods
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    helloFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_bqt_hellofromc_MyNativeMethods_helloFromC
  (JNIEnv *, jobject);
/*
 * Class:     com_bqt_hellofromc_MyNativeMethods
 * Method:    passwordFromC
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_bqt_hellofromc_MyNativeMethods_passwordFromC
  (JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif  

3、在jni目录中编写所需的.c文件【这一步才是核心】

在项目根目录下创建【jni文件夹】,在jni文件夹中创建一个【.c文件】,在c代码中,实现上面定义的本地方法
在.c文件中引入上面生成的.h文件(非必须,个人觉得有用的东西就是,它帮我们自动生成了符合JNI规范的方法声明,我们只需把方法声明拷走就行了)
#include "com_bqt_hellofromc_MyNativeMethods.h"  

以下为.c中的代码
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>//必须添加的头文件

jstring Java_com_bqt_hellofromc_MyNativeMethods_helloFromC(JNIEnv* env, jobject obj) { //【返回值】【方法名】【参数列表】返回值类型jstring就是java中的string
    char* cstr = "hello from c"; //  char*  在c中可用来表示一个字符串。注意,这里绝对不能有中文
    jstring jstr = (*env)->NewStringUTF(env, cstr);
    return jstr;
}

JNIEXPORT jint JNICALL Java_com_bqt_hellofromc_MyNativeMethods_passwordFromC(JNIEnv *env, jobject obj, jint a, jint b) {
//JNIEXPORT和JNICALL都是JNI的关键字,表明函数是被JNI调用的;JNIEXPORT 表示输出类型;JNICALL表示参数的压栈顺序;貌似都可以省略
    return a + b + 10000; //c中的int占用字节数在不同环境下可能不同,可能是0-65535,所以,稍微大一点的数(十万级别)都得用double
}

4、在jni目录中创建Android.mk文件,主要是声明所引用的.c文件和生成的.so库的文件名

在工程的jni目录下创建一个【Android.mk文件】,在里面定义打包成函数【库的名字】及对应的【c代码的文件名】
LOCAL_PATH := $(call my-dir)
# C/C++代码所在目录,也就是我们的jni目录,不必修改
include $(CLEAR_VARS)
LOCAL_MODULE    := hello
# 对应打包成函数库的名字,编译器会自动在前面加上lib,在后面加上.so,最终结果就是libhello.so
LOCAL_SRC_FILES := hello.c
# 对应的c代码的文件名,即hello.c  
include $(BUILD_SHARED_LIBRARY)

5、创建Application.mk文件,主要是声明所有支持的平台

默认只会生成支持arm平台的动态链接库文件,若项目要支持arm外的平台,需在jni目录中添加【Application.mk】文件,并加上以下内容
APP_ABI := armeabi armeabi-v7a x86
#Application.mk文件的目的是,描述在你的应用程序中所有需要的模块(即静态库或动态库)
#APP_ABI 的值以空格区分,代表要支持的架构,默认值为【armeabi】。其他架构,ARMv7 【armeabi-v7a】;IA-32【 x86】
#每增加一个架构,编译后都会在lib目录下生成一个相应的文件夹,文件夹下的文件都是同名的.so文件(当然文件内容不一样)

编译成功后,会在lib目录下生成对应的多个文件夹及.so文件

6、使用ndk工具编译生成.so成动态链接库文件

可以使用cygwin工具编译,其中下面第三步中为Android工程的根目录
cd ../.. cd cygdrive/ cd D/Users/Android_workspace/HelloFromC ndk-build 或直接用cmd编译,注意要先在"系统变量path"中增加NDK工具所在路径,如【D:\Android\android-ndk-r10d】 cd/d D:\Users\Android_workspace\HelloFromC ndk-build
过程:


编译成功后会在工程libs/armeabi目录下生成一个【libhello.so】文件
其中,eabi的含义为:Embedded Application Binary Interface(嵌入式应用二进制接口)

细心观察会发现,除了自动生成了libs目录下的.so文件外,还产生了一个比libs目录大很多倍的obj目录,并且其结构及内容也很像

网上找到的资料解释为:
As part of the build process过程, the files in the libs folder have been stripped剥皮 of symbols符号 and debugging information. So you'll want to keep two copies of each of your .so files: One from the libs folder to install on the Android device, and one from the obj folder to install for GDB一个调试工具 to get symbols from.

简单来说就是,obj下的是带符号和调试信息的,lib下的是去掉这些庞大信息后的动态链接库文件,在安装到Android设备上时只需libs目录下的.so文件即可

当完成这一步后,如果我们以后不需要再重新编译,我们就可以直接删除【jni】目录和【obj】目录了

以下是是发布前的工程结构


7、使用时,直接调用本地native方法即可

在java代码中加载.so类库,之后就可以调用本地方法了
public class MainActivity extends ListActivity {
    static {
        System.loadLibrary("hello");// 在java代码中引入libs目录下的库函数,文件名为【libhello.so】。注意,引入时的文件名要去掉前面的lib和后面的.so
    }

    private TextView tv_info;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = { "调用C中的无参方法,返回一个字符串", "调用C中的有参方法,返回处理1+2后的值", };
        tv_info = new TextView(this);
        tv_info.setTextColor(Color.BLUE);
        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv_info.setPadding(20, 10, 20, 10);
        getListView().addFooterView(tv_info);
        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            String stringFromC = MyNativeMethods.getInstance().helloFromC();
            tv_info.setText(stringFromC);
            break;
        case 1:
            int intFromC = MyNativeMethods.getInstance().passwordFromC(1, 2);
            tv_info.setText(intFromC+"");
            break;
        }
    }


附件列表

JNI 详细使用 基础【步骤】的更多相关文章

  1. android之ListView,详细介绍实现步骤,举例,自定义listview适配器

    android之ListView,详细介绍实现步骤,举例,自定义listview适配器 本文来源于www.ifyao.com禁止转载!www.ifyao.com android中如何使用listVie ...

  2. 部署Bookinfo示例程序详细过程和步骤(基于Kubernetes集群+Istio v1.0)

    部署Bookinfo示例程序详细过程和步骤(基于Kubernetes集群+Istio v1.0) 部署Bookinfo示例程序   在下载的Istio安装包的samples目录中包含了示例应用程序. ...

  3. 测试那些事儿—Linux搭建环境基础步骤

    Linux搭建环境基础步骤 准备工具:SecureCRT工具(Linux工具,连接服务器)FTP传输工具(上传文件到服务器)MySQL连接工具 安装包(以下文件均为压缩包rpm格式和tar.gz):J ...

  4. 接下来将介绍C#如何设置子窗体在主窗体中居中显示,本文提供详细的操作步骤,需要的朋友可以参考下

    接下来将介绍C#如何设置子窗体在主窗体中居中显示,本文提供详细的操作步骤,需要的朋友可以参考下 其实表面上看是很简单的 开始吧,现在有两个窗体Form1主窗体,Form2子窗体 而且我相信大部分人都会 ...

  5. 详细故障排除步骤:针对 Azure 中到 Windows VM 的远程桌面连接问题

    本文提供详细的故障排除步骤,用于为基于 Windows 的 Azure 虚拟机诊断和修复复杂的远程桌面错误. Important 若要消除更常见的远程桌面错误,请务必先阅读远程桌面的基本故障排除文章, ...

  6. JNI 详细使用步骤 上手示例

    1.定义本地native方法 定义本地方法,通常情况下,应单独定义一个类来封装所有native方法 /** 存放native方法的类 */ public class MyNativeMethods { ...

  7. js最详细的基础,jquery 插件最全的教材

    一.Js的this,{},[] this是Javascript语言的一个关键字,随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this指的是调用的函数自己. { } 大括号 ...

  8. Android(java)学习笔记259:JNI之NDK开发步骤

    1. NDK开发步骤(回忆一下HelloWorld案例): (1)创建工程 (2)定义native方法 (3)创建jni文件夹 (4)创建c源文件放到jni文件夹 (5)拷贝jni.h头文件到jni目 ...

  9. JNI 详细解释

    JNI事实上,Java Native Interface缩写,那是,java本地接口.它提供了许多API实现和Java和其它语言的通信(主要是C&C++). 或许不少人认为Java已经足够强大 ...

随机推荐

  1. 命令:which、whereis、who和w

    开始 命令搜索的顺序 在shell function中查找,有则调用,无则下一步: 判断命令是否为bash内置命令,有则调用,无则下一步: 在$PATH中搜索该命令,有则调用,无则报错. 判断命令类型 ...

  2. [flask]flask_login模块,session及其他

    读flask源码的时候,有一点一直到现在都没有一个清晰的概念,比如四个全局变量g,current_app,session,request是怎么做到的 按照查到的资料里面的说法,为了不至于每次都主动调用 ...

  3. 4040 EZ系列之奖金

    4040 EZ系列之奖金 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 钻石 Diamond   题目描述 Description 由于无敌的WRN在2015年世界英俊帅气男总决选中 ...

  4. 20162303 解读同伴的收获&解决同伴的问题 周三补交

    解读同伴的收获&解决同伴的问题 11月29号 解决同伴的问题 我的同组同学是20162307学号张韵琪同学 同组同学的问题是动态规划算法步骤中递归定义的最优值 我理解他的意思是她不太理解最优值 ...

  5. bzoj 3669 lct维护最小生成树

    大概题意:给一个无向图,有a,b两种边权,找一条从1到n的路径,使得max(a[i])+max(b[i])最小a[i],b[i]表示该路径上的边的对应权. 如果用类似最短路的DP来做,显然每个点的状态 ...

  6. 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 312  Solved: 193[Submit][Status][Discuss] ...

  7. flask 中 session的源码解析

    1.首先请求上下文和应用上下文中已经知道session是一个LocalProxy()对象 2.然后需要了解整个请求流程, 3.客户端的请求进来时,会调用app.wsgi_app(),于此此时,会生成一 ...

  8. 电子助视仪 对比增强算法 二十种色彩模式(Electronic Video Magnifier, 20 color mode)

    电子助视仪 是一种将原始彩色图像转换为某种对比度高的图像,例如将原始图像变换为黑底白字,红底白字,白底红字,蓝底黄字,黄字蓝底等等.电子助视仪的主要应用场景为为老人或者特殊弱视人群的阅读.国内国外均有 ...

  9. MYSQL-5.5.37-win32.msi 这个版本得程序包谁有吗 可以给我一下吗?

    之前下载了这个版本得mysql   但是跟服务器链接不上   后来我就卸载了  但由于卸载不干净  现在又删了注册表   好像把这个程序包得什么文件删除了  现在提示配置文件错误  所以有这个程序包得 ...

  10. LogStash日志分析系统

    简介 通常日志管理是逐渐崩溃的——当日志对于人们最重要的时候,也就是出现问题的时候,这个渐进的过程就开始了.日志管理一般会经历一下3个阶段: 初级管理员将通过一些传统工具(如cat.tail.sed. ...