android JNI学习一

记录一下自己学习JNI的过程,目标是做一个小demo,实现apk简单调用C或C++语言,从而熟悉JNI过程。并记录错误。可以实现java调用C或C++语言,并且从C或C++回调java。

以下为个人观点,未必正确,可不参考

JNI就是java调用本地方法的意思,具体来说就是android apk里java调用.so为后缀的库文件里的C或C++函数。

我个人认为java调用C有两种,一种是java函数映射成C语言函数,类似于注册。另一种是直接通过apk包名实现定义。

一开始选择在网上找到最多的方法,就是直接包名绑定定义。

首先,参考网上的一个编译独立so库来调用jni的方法:Android源码中编译自己的so库 -- http://www.linuxidc.com/Linux/2013-02/79007.htm

由于本人比较喜欢用系统代码编译文件,因此选用了这个参考例子来编译so库文件,从而调用。其实应该也可以搭建NDK开发环境来使用JNI,但本人还没搭建环境,所以这种尝试等以后再弄。

本人的开发环境是在ubuntu系统下,对于这个例子我先略记录一下我自己的学习过程,首先是在系统根目录下/packages/apps/里建立一个文件夹jni_test,文件夹里按照例子来新建

tools.h文件

代码:

#ifndef TOOLS_H
#define TOOLS_H

extern int add(int add1, int add2);

#endif

然后新建

tools.c文件

代码:

#include "tools.h"

int add(int add1, int add2){
    return add1 + add2;
}

新建

jni_call.c文件

代码

#include "tools.h"
#include <jni.h>

jint
Java_com_eton_helloworld_MainActivity_add(JNIEnv* env, jobject this, jint add1, jint add2){
    return add(add1, add2);
}

新建

Android.mk文件

内容:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libtools
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := tools.c
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libjnicall
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := jni_call.c
LOCAL_STATIC_LIBRARIES := libtools
include $(BUILD_SHARED_LIBRARY)

打开终端进入android系统根目录,设置编译环境,然后开始编译这个文件夹,输入 mmm packages/apps/jni_test/并回车,如下

/q8625$ mmm packages/apps/jni_test/(说明,$表明我不是在超级用户模式下,#就表示在超级用户模式下,这个对我而言无所谓)

编译完成提示:Install: out/target/product/msm8625/system/lib/libjnicall.so

这时在/out/target/product/msm8625/system/lib 文件夹内就会生成一个libjnicall.so的库文件,这就是让java加载的lib库。

编译完so库后,把so库push到测试机器里面(本人使用实体机来测试,并不是使用虚拟机,在机器的system目录下新建一个jni文件哟难于存放so库): adb push libjnicall.so /system/jni/

然后打开eclipse新建一个android工程,就一个最简单的hellowork工程,包名为com.example.jnicall 这里注意在包名里不要有_(下横杠)出现,因为后面的jni方法会有影响。

MainActivity.java文件代码:

package com.example.jnicall;


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

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

编译工程跑起来就一句hello world就可以了。在onCreate函数下增加加载lib库函数,并且定义jni接口函数。代码如下:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
add(1,2);
}

static {
System.load("/system/jni/libjnicall.so");
}
public native int add(int add1, int add2);
}

保存并编译程序,用终端打印log会发现报错,错误截取:java.lang.UnsatisfiedLinkError: Native method not found: com.example.jnicall.MainActivity.add:(II)I

这个错误是java调用add函数时出错,为什么呢?是因为jni库里缺少了东西。

重新打开jni_call.c文件,修改如下:

#include "tools.h"
#include <jni.h>
#include "JNIHelp.h"
Java_com_example_jnicall_MainActivity_add(JNIEnv* env, jobject this, jint add1, jint add2){
    return add(add1, add2);
}

#ifdef __cplusplus
extern "C" {
#endif
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
    return JNI_VERSION_1_4;
}
#ifdef __cplusplus
} // extern "C"
#endif

主要是添加JNI_OnLoad函数。和"JNIHelp.h"这个头文件。修改add函数名,注意,这个函数名是Java_com_example_jnicall_MainActivity_add,前面的Java的J一定要大写,后面是接java的包名和native 函数名(包名com.example.jnicall变成com_example_jnicall),包名里的 . 要用 _ 替换,这时就知道为什么建工程时不要有 _ 了。然后保存编译,重新把so库push进机器里。再编译运行apk,就发现apk能跑了,如果添加log,就能发现已经调用了jni_call.c里的add函数。这个就是较为简单的jnni方法实例。


我把工程代码放上共享:http://download.csdn.net/detail/u013820413/6991951  不需要积分,由于是ubuntu压缩,所以没试过windows解压是否会出错。


参考资料:使用NDK移植开源项目,JNI的使用技巧 http://terryblog.blog.51cto.com/1764499/792442

Android的NDK开发(1)————Android JNI简介与调用流程 http://blog.csdn.net/conowen/article/details/7521340


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值