JNI_2
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI_2相关的知识,希望对你有一定的参考价值。
JNI开发的流程
①交叉编译的概念
Java 调用 C/C++
C/C++ 本地语言 特点 平台相关性强
windows上编写 能在linux上运行的 本地代码
交叉编译 在一个平台上编译出另一个平台可以执行的本地代码
平台 CPU平台 X86(Intel AMD) ARM(高通骁龙 华为 海思 麒麟 三星 MTK)99%android设备
mips 嵌入式设备上
操作系统平台 windows linux max OS unix 类unix
不同平台支持的native code不同
交叉编译的原理就是在一个平台上模拟另外一个平台的特点进行编译
在windows上编写能够在android上运行的本地代码
NDK native develop kit
NDK目录的结构
NDk Helloworld
NDK开发相关文档&案例下载
https://developer.android.google.cn/ndk/index.html
JNI开发通用流程 NDK-BUILD(studio eclipse都可以使用的方法)
①在java代码中声明native 方法 native方法没有实现
//用native关键字声明本地方法 本地方法不用实现
public native String helloFromC();
②在模块根目录下(如果是eclipse就是在项目的根目录下)创建jni文件夹,在文件夹中创建.c的源代码
#include<stdio.h>
#include<stdlib.h>
#include<jni.h>
//
// Created by fullcircle on 2017/2/18.
//
//java程序还是应用的入口 在C中只是实现一些函数 等待着java去调用
//native函数命名规则 Java_包名_类名(包含native方法的java类)_native方法名
//JNIEnv* env
//JNIEnv 是结构体 JNINativeInterface的一级指针
//env是JNIEnv的一级指针 所以env就是结构体JNINativeInterface的二级指针
//JNINativeInterface 这个结构体中声明了大量的函数指针 这些函数指针在Jni开发中做用非常重要
//jobject thiz 哪个java对象通过jni调用到这个方法 这个jobject 就是这个java对象
//对于当前的案例来说 这个jobject就是MainActivity
//jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
// jobject thiz )
//JNIEnv* env,jobject thiz 这两个参数是必须传入的
jstring Java_com_itheima_jni97_MainActivity_helloFromC(JNIEnv* env,jobject thiz){
char* cstr = "hello from c!!!!";
//NewStringUTF 作用把c的字符串(char* 类型)转换成java的字符串
//jstring (*NewStringUTF)(JNIEnv*, const char*);
//return (**env).NewStringUTF(env, cstr);
return (*env)->NewStringUTF(env, cstr);
}
③ 在jni目录下创建一个Android.mk文件
#LOCAL_PATH 获取当前路径
LOCAL_PATH := $(call my-dir)
# 清除上次编译获取的编译环境变量 会保存LOCAL_PATH
include $(CLEAR_VARS)
#指定编译生成的模块叫什么名字
LOCAL_MODULE := hello-jni
#指定要编译的.c源文件叫什么名字
LOCAL_SRC_FILES := hello.c
#生成动态链接库 .so文件
include $(BUILD_SHARED_LIBRARY)
Android.mk文件作用 向编译系统描述 我要编译的文件在什么位置 叫什么名字 要生成的文件叫什么名字 是什么类型
④在项目的根目录下调用ndk-build编译项目
如果是studio环境 还需要指定 NDK_PROJECT_PATH=app
编译成功后会在libs目录下创建一系列文件夹 包含了生成的.so文件
⑤在运行之前 需要通过System.loadLibrary加载.so文件 注意加载.so文件 文件名字不包含lib前缀和.so后缀
⑥如果是studio环境 需要在模块的.gradle文件中加上如下内容
sourceSets.main.jniLibs.srcDirs = [‘libs‘] 放到android{}中
JNI开发常见错误
①Caused by: java.lang.UnsatisfiedLinkError: Native method not found 本地方法没有找到
出现原因 c函数名字 不符合 Native函数的命名规则
解决办法 用javah生成头文件
javah使用方法 到模块的src/main/java 目录下运行javah
格式 javah 包含native方法的java类的全类名
原因2忘记使用System.loadlibrary加载.so文件
解决办法:使用静态代码块在Activity加载的时候就把.so文件加载进来
static {
System.loadLibrary("hello-jni");
}
②java.lang.UnsatisfiedLinkError: Couldn‘t load libhello-jni from loader ....findLibrary returned null
出现原因 在System.loadlibrary加载.so文件 文件名字写错
原因2 当前的.so不支持设备的cpu平台 解决方法 在jni目录下创建Application.mk 指定当前应用的.so支持哪些cpu平台
APP_ABI := armeabi x86
如果使用NDK-build做jni开发 Android.mk Appliction.mk 尽量ctrl+c ctrl+V
studio中NDK-Build简便流程
①在java代码中声明native方法
②在main目录下创建jni目录 并且创建一个Android.mk
③右键单击模块 选择如下内容
实际上就是在build.gradle中加入了如下内容
android{
......
externalNativeBuild {
ndkBuild {
path ‘src/main/jni/Android.mk‘
}
}
}
④编写C的代码 这个时候C的代码就有提示了
⑤ System.loadLibrary("")加载对应的.so文件
⑥ 运行模块 不用单独编译
CMake方式进行NDK开发
项目创建出来之后 会在模块的根目录下创建一个CMakeLists.txt 构建脚本
项目创建之后手动加入CMake支持
点击ok之后就会添加cmake的支持
实际上就是在gradle文件下添加如下内容
向logcat输出日志:
①Android.mk文件增加以下内容 LOCAL_LDLIBS += -llog
如果是CMake方式 studio帮助创建的CMakeLists.txt文件中已经加入了导入liblog的内容不需要特殊配置
②C代码中增加以下内容 #include <android/log.h> #define LOG_TAG "System.out" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) C代码中使用logcat, 例: LOGI("info\\n"); LOGD("debug\\n");
以上是关于JNI_2的主要内容,如果未能解决你的问题,请参考以下文章