Android学习笔记-NDK开发(一)
来源:互联网 发布:怎样申请旺旺淘宝账号 编辑:程序博客网 时间:2024/05/16 05:19
在一些老的项目或老的Android教程中,有可能还使用着本篇文章所描述的方式来创建一个Android NDK项目,所以,就写了此篇文章以供参考。
下面以AS中一个简单的例子来按步骤说明:
第一步:创建一个新的Android项目(此处不勾选“include C++ support”,只按普通项目创建)。
第二步:在“src/main/java/你的包名”中,新建一个调用NDK函数的Java类,并且在Java类中定义(与NDK函数名称相同的)native方法。
package com.lonly.example.ndkdemo2;public class MyNDK { public static native int sequare(int num); static { //参数是.so库的名称:libJniDemo.so 的名称为JniDemo System.loadLibrary("JniDemo"); }}第三步:准备头文件(.h)。
在AS的Terminal面板,输入命令定位到上一步所创建Java类的根目录,使用下面的命令自动生成头文件javah -jni -encoding UTF-8 com.lonly.example.ndkdemo2.MyNDK(全类名),按回车键,系统会自动在“src/main/java/”目录下生成一个.h文件。
打开后是这样子的:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_lonly_example_ndkdemo2_MyNDK */#ifndef _Included_com_lonly_example_ndkdemo2_MyNDK#define _Included_com_lonly_example_ndkdemo2_MyNDK#ifdef __cplusplusextern "C" {#endif/* * Class: com_lonly_example_ndkdemo2_MyNDK * Method: sequare * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_lonly_example_ndkdemo2_MyNDK_sequare (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif里面声明了我们定义的native方法。
第四步:创建jni目录,将生成的.h头文件移动到这个目录。
第五步:在jni目录下创建cpp文件,实现.h文件中的函数。
代码:
#include "com_lonly_example_ndkdemo2_MyNDK.h"//计算一个整数的平方JNIEXPORT jint JNICALL Java_com_lonly_example_ndkdemo2_MyNDK_sequare (JNIEnv *env, jclass clz, jint num){ return num * num; }第六步:设置local.properties文件,指定Androidndk的根目录位置 (ndk.dir=E\:\\AndroidSDK\\ndk-bundle)。
## This file is automatically generated by Android Studio.# Do not modify this file -- YOUR CHANGES WILL BE ERASED!## This file must *NOT* be checked into Version Control Systems,# as it contains information specific to your local configuration.## Location of the SDK. This is only used by Gradle.# For customization when using a Version Control System, please read the# header note.#Wed Oct 25 16:32:30 CST 2017ndk.dir=E\:\\AndroidSDK\\ndk-bundlesdk.dir=E\:\\AndroidSDK
第七步:设置build.gradle文件,编译NDK程序,生成libJniDemo.so文件。
ndk{ moduleName "JniDemo" }
第八步:gradle.properties文件中加入android.useDeprecatedNdk=true。
第九步:调用NDK函数。
public class MainActivity extends AppCompatActivity { // JAVA_packagename_classname_functionname // jstring String jint int //1.建立一个调用NDK函数的Java类,并且在Java类中定义与NDK函数名称相同的native方法 //2. 准备头文件(.h) // 使用下面的命令自动生成头文件javah -jni -encoding UTF-8 com.lonly.example.ndkdemo2.MyNDK //3.创建jni目录,将头文件移动到这个目录 //4.在jni目录下创建cpp文件,实现.h文件中的函数 //5.设置local.properties文件,指定Androidndk的根目录位置 ndk.dir=E\:\\AndroidSDK\\ndk-bundle //6. 设置build.gradle文件,编译NDK程序,生成libJniDemo.so文件 //7.调用NDK函数 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.textview); tv.setText(String.valueOf(MyNDK.sequare(21))); }}
知识拓展:
1..h文件中声明的函数参数JNIEnv与JavaVM、jclass与jobject。参考http://blog.csdn.net/freechao/article/details/7692239
- JNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立。JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线程都可以使用这个JavaVM。当后台线程需要调用JNI native时,在native库中使用全局变量保存JavaVM尤为重要,这样使得后台线程能通过JavaVM获得JNIEnv。native程序中频繁使用JNIEnv*和JavaVM*。
- 当NDK方法声明为static静态方法时,参数使用jclass,非静态时,使用jobject。
2.javah命令生成.h头文件时报错误“错误: 编码GBK的不可映射字符”。
解决方法:应该使用-encoding参数指明编码方式,如:
javah -jni -encoding UTF-8 com.example.XXXX.XXXX.MainActivity
3.编译运行时,出现以下异常:
Error:Execution failed for task ':app:compileDebugNdk'.> Error: Your project contains C++ files but it is not using a supported native build system. Consider using CMake or ndk-build integration with the stable Android Gradle plugin:https://developer.android.com/studio/projects/add-native-code.html or use the experimental plugin:http://tools.android.com/tech-docs/new-build-system/gradle-experimental.Information:BUILD FAILEDInformation:Total time: 1.303 secsInformation:1 errorInformation:0 warningsInformation:See complete output in console
这是因为项目中包含了jni文件夹和jni文件夹中需要ndk-build的c文件,AS会调用ndk-build去编译这些jni代码,但项目中却没有将“useDeprecatedNdk”设为true。解决方法:在gradle.properites中添加“android.useDeprecatedNdk=true”。
4.生成的.so文件的位置,如何使用.so文件?
源码传送门:https://github.com/legallonly/NDKDemo2此时AS每次编译build时会将jni中的代码编译成静态库并放到app/build/intermediates/ndk/debug/lib/下,APP运行时所调用的so库就是该目录下的so库,如果想只留下so库,而不再需要jni代码,需要做的是:①删除jni文件夹;②将app/build/intermediates/ndk/debug/lib/下已经编译好的so库拷贝至app/libs中,指定so存放目录build.gradle->sourceSets;③注释掉gradle.properites中android.useDeprecatedNdk=true。
- Android学习笔记-NDK开发(一)
- Android NDK 开发系列 学习笔记(一)
- Jni开发与Android NDK开发学习笔记(一)
- Android NDK 学习笔记(一)
- Android NDK 开发(笔记一)
- Android NDK开发学习(一)
- Android学习笔记-NDK开发(二)
- Android NDK 学习笔记(一)
- android NDK开发学习笔记
- NDK开发笔记(一)
- 我的NDK学习开发笔记(一)
- NDK学习笔记(一)
- NDK开发学习(一)
- android NDK开发(一)
- Android-NDK开发(一)
- android NDk开发学习一<简单实现>
- Android NDK (学习笔记一) —— 认识NDK
- Android学习笔记之NDK开发环境配置(WIN32)
- 2006年培养学员8万人,每年增长%25,请问按此增长速度,到那一年培训学员人数将达到20万人用for,while,dowhile,实现
- 论文阅读:《Pyramid Scene Parsing Network》CVPR 2017
- 模式开始-第四天
- 如何在html中直接给某个按钮置灰(样式、去除绑定事件), querySelector与jquery selector的不同之处
- AngularJs实现增加订单、批量发货
- Android学习笔记-NDK开发(一)
- redis相关总结
- 学习网站
- 每日一练10.20
- PAT甲级1008. Elevator(20)
- ElasticSearch在JPA与原生操作接口的对应关系
- DrawerLayout 的点击事件
- ORA-00257:archiver error.Connect internal only, until freed
- FPGA与VHDL 小结