当前位置: 代码迷 >> Android >> Android幼功:JNI
  详细解决方案

Android幼功:JNI

热度:118   发布时间:2016-04-27 22:22:57.0
Android基本功:JNI
??

一、什么是JNI 

  • Java本地开发接口(Java Native Interface); 

  • 用来沟通Java代码和外部的本地代码(c/c++)。通过这个协议,Java代码就可以调用外部的c/c++代码,外部的c/c++也可以调用Java代码; 
     

图像

二、为什么使用JNI 

  • Java语言装载到虚拟机中,不能和硬件交互,不能驱动开发。JNI扩展了Java虚拟机的能力,驱动开发(如wifi-hotspost)无线热点共享; 

  • Native Code效率高,数学运算、实时渲染的游戏,音视频处理(如极品飞车,opengl); 

    • C代码手动回收内存,程序员可以控制,及时回收内容; 

    • Java代码自动回收,程序员没法控制,基于算法; 

  • 复用代码(文件压缩,人脸识别Opencv,7zip,ffmpeg); 

  • 特殊应用场景,如电视、车载系统、微波炉等; 

    • 汽车监控系统,传感器基于电信号; 

 

三、NDK是什么 

  • Native develop kits工具链,提供了交叉编译的工具链; 

  • C语言不跨平台,在Windows系统下使用NDK编译在Linux下能执行的函数库; 

    • dll:Windows系统下的函数库文件; 

    • so:Linux系统下的函数库文件; 

  • 在Linux电脑(x86架构)开发,需要使用NDK编译在手机cpu(arm架构)能执行的函数; 

 

四、怎么使用NDK 

  1. 在官网下载适应版本的Ndk包(android-ndk-r10e-windows-x86_64.exe文件),双击改文件即会自动解压(android-ndk-r10e文件夹,非中文目录); 

  2. 在环境变量path中添加ndk的目录(D:\DevelopTools\android-ndk-r10e); 

  3. 在cmd命令窗口执行ndk-build命令,有如下输出则安装成功 

图像

 

五、NDK目录结构 

  • Builds:ndk搭建的环境; 

  • Docs:ndk开发的文档; 

  • Platform: 

    • arm:英国arm公司,不生产cpu,卖cpu的架构转移,功耗比较低; 

    • Mips:cpu架构,龙心; 

    • X86:inter,没有特别明显的优势,运行效率高点,功耗比较大; 

  • Samples:提供示例代码; 

  • Sources:ndk的源码 

  • Toolchains:交叉工具的工具链; 

  • ndk-build.cmd:交叉编译的批处理文件; 

 

六、JNI协议规范 

  • 规定了Java类型和c类型的转化; 

java 

在jni中的别名 

c代码 

boolean 

jboolean 

unsigned char 

float 

jfloat 

float 

double 

jdouble 

double 

byte 

jbyte 

signed char 

char 

jchar 

unsigned short 

short 

jshort 

short 

int 

jint/jsize 

int 

long 

jlong 

long long 

Object 

jobject 

void * 

String 

jstring 

void * 

  • Struct JNINativeInterface 结构体重定义了java的底层方法,底层方法通过c代码实现的; 

  • Runtime虚拟机 对之前的虚拟机做了优化; 

 

七、JNI的开发流程 

  1. 写c代码突破口native,类似于抽象方法,具体实现由c代码来实现 

public native String helloFromC(); 

  1. 创建jni目录,在jni目录中创建c代码,让c代码找到对应的native方法 

#include <jni.h> 

jstring Java_com_example_hellojni_MainActivity_helloFromC(JNIEnv* env,jobject obj){ 

    jstring jstr=(*env)->NewStringUTF(env,"Hello"); 

    return jstr; 

} 

  1. 在jni目录下,创建Android.mk文件 

#$ linux执行方法的符号  返回当前的工程目录 

LOCAL_PATH := $(call my-dir) 

# 清除所有之前的缓存,清除是local开头的变量  唯一不会清除LOCAL_PATH 

include $(CLEAR_VARS) 

#代表打包生成的函数库的名字  前面自动生成lib 后面自动生成.so  如果前面+上lib 不会再生成lib 

LOCAL_MODULE:= hello-jni 

# 代表要把哪个c文件打包成函数库  

LOCAL_SRC_FILES:= hello.c  

# BUILD_SHARED_LIBRARY  生成动态函数库  .so   体积小    把系统的c程序动态加载  

# BUILD_STATIC_LIBRARY  生成静态函数库  .a    体积大   把用到的系统的c代码 一次性加载到函数库中 

include $(BUILD_SHARED_LIBRARY) 

  1. 交叉编译,在cmd控制台,进入当前工程目录下,执行ndk-build指令 

图像
  1. 在java在代码中引入函数库,直接调用native方法 

static{ 

    //不管android.mk文件是怎么写的  就是去掉已有的函数库的lib  .so 

    System.loadLibrary("hello-jni"); 

} 

 

@Override 

protected void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 

    setContentView(R.layout.activity_main); 

    Toast.makeText(getApplicationContext(), helloFromC(), 0).show(); 

} 

 

八、NDK的简单开发流程 

  1. 配置Eclipse的NDK路径; 

图像
  1. 创建Android项目,右键Android项目->Android Tools->Add Native Support; 

图像
  1. 添加完成native方法,在PrjectDir/scr目录下执行javah命令。生成标头文件com_example_hellojni2_MainActivity.h,并且拖拽到jni目录下 

图像
  1. 将hellojni2.cpp文件修改为hello.c文件,并且将com_example_hellojni2_MainActivity.h文件中生成的方法,粘贴到hellojni2.c文件中,如下; 

#include "com_example_hellojni2_MainActivity.h" 

 

jstring Java_com_example_hellojni2_MainActivity_helloFromC(JNIEnv *env, jobject obj){ 

    jstring jstr=(*env)->NewStringUTF(env,"Hello"); 

    return jstr; 

} 

  1. 修改Android.mk文件中的相关配置后,点击“小锤子”生成hello-jni2.so文件; 

图像
  1. 同上,在MainActivity中调用hello-jni2.so文件中的c方法; 

 

九、NDK常见错误 

  1.  没有引入函数库/c代码和java代码不对应 

11-02 14:47:33.259: E/AndroidRuntime(1185): java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.example.hellojni2.MainActivity.helloFromC() (tried Java_com_example_hellojni2_MainActivity_helloFromC and Java_com_example_hellojni2_MainActivity_helloFromC__) 

  1. 没有Android.mk文件 

D:\DevelopTools\android-ndk-r10e\ndk-build.cmd all  

Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml     

Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk     

D:/DevelopTools/android-ndk-r10e/build/core/add-application.mk:199: *** Android NDK: Aborting...    .  Stop. 

  1. c代码有编译时错误 

Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml     

[armeabi] Compile thumb  : hello-jni2 <= hello.c 

jni/hello.c: In function 'Java_com_example_hellojni2_MainActivity_helloFromC': 

jni/hello.c:4:2: error: unknown type name 'a' 

  a 

  ^ 

jni/hello.c:5:10: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'jstr' 

  jstring jstr=(*env)->NewStringUTF(env,"Hello"); 

  1. c代码有运行时异常 

 

十、跨CPU的开发 

  1. 在jni目录下添加Application.mk文件,定义支持的CPU类型; 

APP_ABI := x86 

APP_PLATFORM := android-8 

  1. 重新交叉编译项目的so文件,会看见在支持的平台下,都会生成so文件,然后运行模拟器; 

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案