android JNI (NDK)的故事
来源:互联网 发布:腾讯高级php面试题 编辑:程序博客网 时间:2024/05/16 17:51
在讲故事之前,先要普及下概念。(懂的人跳过~)
C/C++是需要经过编译,连接,一个.c文件需经过至少两步之后才生产一个可执行文件。用.c进行举例。
文件后缀(Window平台)
文件后缀(Linux平台)
源文件
.c
.c
头文件
.h
.h
中间件
.object
.o
静态库
.lib
.a
动态库
.dll
.so
可执行文件
.exe
一般无后缀
因为跟Android相关,主要就介绍linux下的C程序
静态库:就是.o进行打包,相当于多个.o组合在一起成了.a,相当于把应该有的东西都包含了,好处是运行块,缺点是体积庞大,替换麻烦
动态库:也是由.o而来,不过运行时才加载的,体积小,可替换,缺点可能是运行稍慢。
在生成各个文件时,需要正确的组织,linux下是通过 makefile文件来组织的。
本文主讲通过命令行来操作生成各种文件!!!
Android studio原生JNI使用CMake,暂且跳过
做以下步骤之前,需要下载过NDK(ndk-build),并将其加入到系统的环境变量里面。
下面开始步入正题,只要有看过JNI里面对应的C函数的人,都可以看到起函数名字是很长,很奇怪的。
步骤一:生成native函数对应的.h文件
假如有一个包名:com.app.demo.jni 包含类Test.java,如果下所示:
package com.app.demo.jni;public class Test { public static native String sayHello();}其在JNI中对应的函数名是这样的:
JNIEXPORT jstring JNICALL Java_com_app_demo_jni_Test_sayHello
(JNIEnv *, jclass);
看这个结构是,是与java代码中的是有对应关系,完全可以手动写出这样的函数名。但是,这简直就是要了老命,多麻烦啊,所以就有java自带的工具,一般在命令行中使用javah这个命令。看看是怎么做的。
首先需要把.java文件进行编译,生成.class文件,在android studio中使用Buid->make project这个按钮,生成的.class文件如下所示:
(不管是在哪种IDE中,反正先找到生成的.class文件的位置)
跳转到包含包名.class文件的目录上,再用javah 包名+类名的操作进行生成.h,其效果如下:
说明:这里是通过IDE直接生成了.class文件,只是可以用javac命令来生产
总之,过程就是先生成.class,再用javah生成头文件
步骤二:生成.so文件(不包含其它的.so的简单使用)
1.先创建一个jni目录,这个目录随便放在哪里(是真的随便放在哪里,没必要跟项目撤上关系)
我放在D:\csdn\jni这个目录下
2.将生成的.h文件放在jni目录下
3.创建一个.c文件,其中代码如下:
#include "com_app_demo_jni_Test.h"JNIEXPORT jstring JNICALL Java_com_app_demo_jni_Test_sayHello (JNIEnv * env, jclass object){ return (*env)->NewStringUTF(env, "JNI:hello world"); }
上面只是 函数声明中加上了形参,函数中的形参名字是随便起的,不过一般就这么叫。
java中的代码是可以C/C++中的代码互相调用的,java的对象类型在C中都有映射关系。
详细了解:https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
4.创建一个Android.mk文件,内容如下
# Copyright (C) 2008 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := Test.cLOCAL_MODULE := testinclude $(BUILD_SHARED_LIBRARY)这里是生成一个.so库,模块名叫test,最终生成的文件会是libtest.so
Android.mk详细了解:http://android.mk/
5.跳转到jni目录,执行ndk-build,效果如下
执行完了后,再回到D:\csdn,会发现多了两个目录libs 和 obj ,两个下面有libtest.so文件,随便选择一个就生成的.so文件。这个时候默认生成的是一个armeabi平台的.so
需要说明是,可以通过NDK_OUT =./test 这样的方式制定obj存放的目录,通过NDK_LIBS_OUT=./mylibs 这样的方式来存放生成的libs。这种参数的指定可以直接将生成so库放在项目中jniLibs中(这种好处就是不要手动的拷贝so库了)
6.使用Application文件(这一步可选,没有执行ndk-build则默认生成armeabi平台的)
APP_OPTIM:=debugAPP_STL:=stlport_static#stlport_sharedAPP_MODULES:=test#for c++11, gnustl_static is bigger than stlport#APP_STL := gnustl_static#APP_CPPFLAGS += -std=c++11APP_ABI := armeabi armeabi-v7a最后的APP_ABI是用来指定平台的。这里指定了两个平台。
7.回到自己的IDE主项目,建立JniLibs,导入.so
8.进行调用
package com.app.demo.jni;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class MainActivity extends AppCompatActivity { static { System.loadLibrary("test"); //defaultConfig.ndk.moduleName } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("test",Test.sayHello()); }}9,运行出结果
大功告成。本文中生成.so的地方和调用的地方是分开的。
10。如果需要向其他人提供包含Native调用 的jar。你就需要导出一个jar和.so。提供给他人使用。
这就是为什么你看到很多跟视频编解码相关的项目都提供的一个.jar和一个.so库了。
这里只是最简单的过程,不包含使用其他的.so或者.a库
整个流程如下:
Android.mk和JNI详情,只给了官网地址,可能后续会慢慢说明,欢迎交流!!
====2017.1.6补充====
以上方式来弄,JNI部分无法很好的调试,实用与小型的简单项目。这个,大神不用IDE也能调好,,只能说,你开心就好!
之前的方式都是采用一个实验性的gradle插件来进行调试,推荐一篇文章(需要翻墙):NDK调试实验性插件
强烈推荐的是Android studio原生支持的调试(CMake 相关):Android studio原生支持NDK
- android JNI (NDK)的故事
- Android SDK、NDK、JNI的简单介绍
- JNI和Android NDK的使用
- JNI和Android NDK的使用
- Android-JNI NDK的学习记录
- Android NDK的入门学习Hello JNI
- Android的SDK,NDK以及JNI
- Android的SDK,NDK以及JNI
- Android NDK&&JNI 编译环境的搭建
- Android中JNI和NDK的使用
- android ndk jni的写法之一
- Android-JNI NDK的学习记录
- Android NDK&&JNI 编译环境的搭建
- Android NDK开发之Jni的数据类型
- Android NDK JNI接口的声明
- Android SDK、NDK、JNI的简单介绍
- Android之JNI NDK开发的常见问题
- android ndk编译jni的配置
- request.getAttribute()与request.setAttribute()与session.setAttribute()
- IOS开发笔记7-C语言基础复习
- Cockroach Design 翻译 ( 八) 严格序列化(线性化)
- STM32--MDK仿真调试:逻辑分析仪的使用
- 设计模式二——原型模式
- android JNI (NDK)的故事
- Cockroach Design 翻译 ( 九) 逻辑Map内容、store和存储
- 写给准备开始作死的自己 :书签记录
- Cockroach Design 翻译 ( 十) 自修复、重平衡
- C#工厂模式-从简单到优雅的几种实践
- android某包的功能突然用不了
- Cockroach Design 翻译 ( 十一) range元数据
- 三序遍历以及Vertical Order
- Cockroach Design 翻译 ( 十二) Raft – Range副本一致性