博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android平台中编写jni模块的方法(3)
阅读量:6860 次
发布时间:2019-06-26

本文共 5816 字,大约阅读时间需要 19 分钟。

这篇文章来说说ndk的使用方法,其实主要是关于ndk的一些编译选项的研究和翻译(其实人家google的文档已经说的很清楚了)。偶选用的测试环境是 slackware 12.0 + android 1.5 r1 for linux + jdk 1.6.0_12,ndk选用的是android 1.5 ndk r1这个版本的(直接解压就行,免安装的)。

1、从ndk安装说起
ndk安装的时候需要运行一 个~/android-ndk-1.5_r1/build/目录下面的一个叫做host-setup.sh的脚本。大略读了一下这个脚本,发现这个主要是 用来生成out/host/host/config.mk文件的。主要用于指定用户操作系统的判断以及支持的编译器类型(设置makefile中的 cc,ar,ld之类的变量)
ndk的目录介绍。
2、ndk的目录结构分析
进入android-ndk-1.5_r1目录,看到如下目录结构:
GNUmakefile: 标准的makefile格式的文件,用于引用build/core/main.mk的编译脚本。
README.TXT:基本的说明,没啥大用,真正有用的文档都在docs目录下面。
apps/:存放带有jni接口的android工程目录(工程里面有利用native关键字定义的java函数)
build/:存放着几乎所有的ndk编译相关的脚本以及必要的静态链接库。
docs/:存放这ndk的所有“官方”文档,每一篇文档对于jni编写者来说这里面的任何一点点资料都是无价的。
out/:存放一些中间的临时文件,例如jni的.c/.cpp文件编译过程中产生的.o文件等。
sources/:存放jni文件的.c/.cpp的源代码文件。
3、基本的使用方法
(1)创建一个android工程
进入apps目录,运行如下命令:
android create project --target 2 --package com.TWM --activity NDKTest --path ./NDKTest/project
通 过命令行创建一个叫做NDKTest的activity,注意这里的--path需要设置为./XXXXX/project这个目录,这个XXXXX目录 主要是为了ndk的make区分不同项目和工程使用的。编写Application.mk文件的时候,一定要把Application.mk写到这个 XXXXX目录下面。
$NDK/apps/<myapp>/Application.mk
另外,编译jni库的时候使用的命令也是如此:
make APP=<your app name>
这里的<your app name>实际上也是这个XXXXX目录。
(2)为工程添加一个jni的java调用接口
进入app/NDKTest/project/src/com/TWM/NdkTest目录,建立一个新的java文件(例如:NDKJni.java),然后把代码写成类似下面这个样子:
package com.TWM.NdkTest ;
public class NDKJni {
    public native int MyFunc(int a, int b) ;
    static {
        System.loadLibrary("NDKjni") ;
    }
}
这里的MyFunc由于是使用native修饰,因此,这个MyFunc函数是一个调用jni的函数。
(3)为java工程编写Application.mk文件
该文件主要放在app/NDKTest目录下,用于告知ndk的编译脚本,当前的程序需要哪个jni模块。
看上去应该是这个样子的:
APP_PROJECT_PATH := $(call my-dir)/project   ---> 当前目录下的project目录包含了jni模块的java接口
APP_MODULES      := NDKTest                               --->当前模块的名字叫做NDKTest
(4)弄清楚java程序的包层次
以当前的这个project为例,就是上面代码中的package com.TWM.NdkTest,定义的类名为NDKJni。因此,根据这个包的层次,可以根据jni文件的函数命名规则定义函数:
JNIEXPORT jint JNICALL Java_com_TWM_NdkTest_NDKJni_MyFunc(JNIEnv * env, jobject thiz, jint a, jint b) ;
当然,手工根据包层次定义jni函数还是很痛苦的,可以借助于javah工具:
mkdir -p apps/NDKTest/project/jni
cd apps/NDKTest/project/jni
javah -classpath "../bin/classes" com.TWM.NdkTest.NDKJni
然后就会自动生成一个叫做com_TWM_NdkTest_NDKJni.h的文件,里面的内容基本上跟手工生成的差不多:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_TWM_NdkTest_NDKJni */
#ifndef _Included_com_TWM_NdkTest_NDKJni
#define _Included_com_TWM_NdkTest_NDKJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_TWM_NdkTest_NDKJni
 * Method:    MyFunc
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_TWM_NdkTest_NDKJni_MyFunc
  (JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
好了,有了这个函数的定义,就可以准备去编写jni了。
(5)进入source目录
建立目录ndktest,然后在里面放置两个文件,一个是随便命名例如a.c,另外一个是一个叫做Android.mk的编译脚本文件。
里面的内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := NDKTest         --->这里是指定jni模块的名字,生成的so库应该叫做libNDKTest.so,这个名字一定要与Application.mk文件中的APP_MODULES相同。
LOCAL_SRC_FILES := a.c
include $(BUILD_SHARED_LIBRARY)  --->这里是告诉编译脚本生成的库是共享库(本身NDK是可以生成动态库和静态库的)。
然后在a.c里面写入的内容如下:
JNIEXPORT jint JNICALL
Java_com_TWM_NdkTest_NDKJni_MyFunc(JNIEnv * env, jobject thiz, jint a, jint b)
{
  return a+b ;
}
(6)开始编译jni模块
首先进入android-ndk-1.5_r1目录,然后运行如下命令:
make APP=NDKTest [回车]
这个时候就会看到它开始编译并且在apps/NDKTest/projects/目录下建立了libs/armeabi/目录,并且把生成的libNDKTest.so拷贝到该目录下。
看到这里或许有人会问,它的编译参数怎么没有,我怎么调试阿?!其实很简单,只要多加一个编译参数即可。
make APP=NDKTest V=1 [回车]
你就会看到如下的输出(偶的测试程序里面把上面说的a.c改成NDKTest.c了,所以看到的内容略有不同):
wayne@wayne:~/android-ndk-1.5_r1$ make APP=NDKTest V=1
Android NDK: Building for application 'NDKTest'
Compile thumb  : NDKTest <= sources/ndktest/NDKTest.c
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc -Ibuild/platforms/android-1.5/arch-arm/usr/include -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__   -Isources/ndktest -DANDROID  -O2 -DNDEBUG -g    -c -MMD -MP -MF out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d.tmp sources/ndktest/NDKTest.c -o out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o
build/core/mkdeps.sh out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d.tmp out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d
SharedLibrary  : libNDKTest.so
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc -nostdlib -Wl,-soname,libNDKTest.so -Wl,-shared,-Bsymbolic  out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o -Wl,--whole-archive  -Wl,--no-whole-archive   build/platforms/android-1.5/arch-arm/usr/lib/libc.so build/platforms/android-1.5/arch-arm/usr/lib/libstdc++.so build/platforms/android-1.5/arch-arm/usr/lib/libm.so   -Wl,--no-undefined   -Wl,-rpath-link=build/platforms/android-1.5/arch-arm/usr/lib /home/wayne/android-ndk-1.5_r1/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a -o out/apps/NDKTest/android-1.5-arm/libNDKTest.so
Install        : libNDKTest.so => apps/NDKTest/project/libs/armeabi
mkdir -p apps/NDKTest/project/libs/armeabi
install -p out/apps/NDKTest/android-1.5-arm/libNDKTest.so apps/NDKTest/project/libs/armeabi/libNDKTest.so
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-strip --strip-debug  apps/NDKTest/project/libs/armeabi/libNDKTest.so
(7)开始编译android本地java程序
进入apps/NDKTest/project目录,然后运行ant debug来生成调试版本的apk包,注意,此时,apk包里面会自动把刚刚生成的libNDKTest.so打包进去的。这一点可以通过把apk文件用unzip命令解包来验证,在此不再赘述。
这就是android-ndk编译jni程序的全过程,确实要比偶在上一篇文章中描述的方法来得简单许多,总结一下:
(a)在apps目录里面创建带有native关键字声明的java项目。(注意,目录需要多打一层,用来放Application.mk文件)
(b)在sources目录里面创建真正的jni模块目录,里面一定要包含一个叫做Android.mk的文件。
(c)在apps里面的Application.mk与sources目录里面的Android.mk在MODULE的名字上一定要“遥相呼应”。
(d)编译的方法是,进入android-ndk-1.5_r1目录,运行make APP=<your app name> V=1生成jni库;其实不止如此,make APP=<your app name> clean也可以清除掉。
但愿这篇文章能够对各位致力于android开发和移植的朋友们有所帮助。

转载于:https://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/13/2348946.html

你可能感兴趣的文章
博弈入门
查看>>
iOS中获取当前时间,设定时间,并算出差值
查看>>
适配 移动 pc 拖拽效果
查看>>
a threadpool by python
查看>>
Callable 与 Future
查看>>
scala学习手记20 - 方法返回类型推断
查看>>
SQL WITH NOCHECK
查看>>
POJ3090 Visible Lattice Points
查看>>
证明积累
查看>>
Linux系统PHP 安装xdebug调试扩展
查看>>
Swiper 中文API手册(转自挨踢前端)
查看>>
数组常用api
查看>>
File i/o2
查看>>
带参有返回值方法-求1!+2!+3!+4!+5!
查看>>
How to take partial screenshot with Selenium WebDriver in python
查看>>
关于学习
查看>>
Testing - 软件测试知识梳理 - 测试阶段
查看>>
[JZOJ3105]拼图
查看>>
浙江自考本科的一些事项(一)
查看>>
DevOps最佳工具集实践
查看>>