前言:
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。
JNI标准至少要保证本地代码能工作在任何Java 虚拟机环境。
官方Android平台架构图:
正如同行人总结所述:Android上层的Application和ApplicationFramework都是使用Java编写,底层包括系统和使用众多的Libraries都是C/C++编写的,所以上层Java要调用底层的C/C++函数库必须通过Java的JNI来实现。
==只有当你必须在同一进程中调用本地代码时,再使用JNI。
那么NDK的好处有哪些?如下:
1、代码的安全性保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大;只用于公司内部核心技术的算法封装;
2、可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的;
3、提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率;
4、便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
NDK以及所需构建工具介绍:
CMake用于使用简单的平台和编译器独立的配置文件来控制软件编译过程,并生成可以在选择的编译环境中使用的本地makefile和工作空间。
CMack工具套件由Kitware创建,以响应对开源项目(如ITK和VTK)的强大的跨平台构建环境的需求。
官方地址:https://cmake.org/ 有兴趣可以简单了解下~
在Mac OS X中,LLDB是Xcode中的默认调试器,支持在桌面和iOS设备和模拟器上调试C,Objective-C和C ++。
LLDB项目中的所有代码都可以使用标准的 LLVM许可证(一种开放源代码“BSD风格”)许可证。
LLDB目前将调试信息转换成clang类型,以便它可以利用clang编译器基础架构。这允许LLDB在表达式中支持最新的C,C++,Objective C和Objective C ++语言特性和运行时间,而无需重新实现任何此功能。在编写表达式的函数,拆卸指令和提取指令详细信息等时,还可以利用编译器来处理 所有ABI细节。
主要优点包括
- C,C ++,Objective C的最新语言支持 ;
- 可以声明局部变量和类型的多行表达式;
- 支持时使用JIT表达式;
- 当JIT不能使用时,评估表达式中间表示(IR)
下面进入正题,如何配置NKD?(手动下载NDK,或通过Android Studio的Project Structure/SDK Location-->Android NDK Location最下面的Download链接下载)
--(请开启你的Android studio ,我的版本 是3.0.1)
下载中截图:
下载完成后,把NDK的目录填进来:
====到此,关于NDK下载安图解完毕~
我们看一下ndk目录各个作用,简单了解下。
- docs: 帮助文档
- build/tools:linux的批处理文件
- platforms:编译c代码需要使用的头文件和类库
- prebuilt:预编译使用的二进制可执行文件
- sample:jni的使用例子
- source:ndk的源码
- toolchains:工具链
- ndk-build.cmd:编译打包c代码的一个指令,需要配置系统环境变量
下面,我们还要确认配置的构建工具以及调试工具是否OK:
#include <string>
extern "C" JNIEXPORT jstring JNICALL Java_com_hingin_l1_hiprint_Display_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "xxx Hello from C++"; return env->NewStringUTF(hello.c_str());
# Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log )
target_link_libraries( # Specifies the target library. native-lib # Links the target library to the log library # included in the NDK. ${log-lib} )
3. 配置app下的build.gradle文件,
externalNativeBuild { cmake { cppFlags "-fexceptions" } }其次:在android标签同级新增:
externalNativeBuild { cmake { path "CMakeLists.txt" } }
4. 新建Activity和对应的布局文件:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:id="@+id/DisplayName" android:layout_width="374dp" android:layout_height="40dp" android:layout_marginTop="16dp" android:background="@color/colorAccent" android:text="NDK 测试调用C程序接口:" android:textColor="@android:color/background_light" android:textSize="30sp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp" /> <Button android:id="@+id/btn_c_api" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:text="调用C接口" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="288dp" android:layout_marginLeft="16dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="76dp" /> <TextView android:id="@+id/id_c_textview" android:layout_width="367dp" android:layout_height="134dp" android:text="调用C接口成功后返回值:" android:layout_marginTop="152dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" /> </android.support.constraint.ConstraintLayout>
Display.java文件的代码:
......
/** * Created by Administrator on 2018/2/1. */ public class Display extends Activity { private Button mButton; // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.display); Intent intent = getIntent(); Bundle bundle = intent.getExtras(); mButton = (Button) findViewById(R.id.btn_c_api); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(Display.this, "Button btn_c_api is onclicked!", Toast.LENGTH_LONG).show(); TextView text = (TextView) findViewById(R.id.id_c_textview); text.setText("name:" + stringFromJNI()); } }); } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringFromJNI();//注意:这行代码如果是红色的(说明java未能调用到native-lib的包,需要前面静态代码块中的System.loadLibrary("native-lib");编译后才会被调用到),需要编译下程序接口解决该问题;
}
上面的代码中:如果 public native String stringFromJNI(); 这行代码是红色的(说明java未能调用到native-lib的包,需要前面静态代码块中的System.loadLibrary("native-lib");编译后才会被调用到),需要编译下程序接口解决该问题;
编译按钮如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hingin.l1.hiprint"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".OpenCVActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Display"> <intent-filter> <action android:name="android.intent.action.EDIT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.cmath.name/vnd.cn.cmath" /> </intent-filter> </activity> </application> </manifest>
最后,给大家附上整体目录结构以及运行成功后的界面截图: