希望记录一下在学习过程中遇到的最新的问题,过于浅薄,希望各位大佬尽量多的提出问题熬。
在Android Studio 2.2 之后,工具中增加了 CMake 的支持,所以在 Android Studio 2.2 之后有2种选择来编译 c/c++ 代码。
-
一种是 ndk-build + Android.mk + Application.mk 的方式
-
另一种是 CMake + CMakeLists.txt 的方式
实现NDK的完整步骤如下:
- 创建Android ndk project,使用
Native
关键字定义Java
方法(即需要调用的native方法)
- 使用
javac
编译上述 Java
源文件 (即 .java文件
)最终得到 .class
文件
- 通过
javah
命令编译.class
文件,最终导出JNI
的头文件(.h
文件)
- 用
C++
实现在 Java
中声明的Native
方法
Activity
加载so库
,使用native
方法
- 生成
.so
库文件
- 执行代码
我初步是跟随大佬帖子里,使用ndk-build进行so库生成,主要有几个问题:
-
javah的指令已经过期,已经嵌入到了javac -h里面
-
在全部配置完后,rebuild Project并不能生成对应so库
-
在搜寻过一堆ndk-build的so库解决方案并且对应改完之后,我生成了so库。但是对应的apk会闪退。。。
接下来我会继续研究关于ndk-build生成so文件的方案,以及问题的解决方案
今天要介绍的是通过Cmake方式进行So文件生成。
如果是新的工程,可以在新建工程时选择,进去直接就能找到对应的jni库和c++写好的helloworld函数,进行修改,或者再加入新的代码就可以。
如果是在原有工程下进行so库的添加操作,可以按照以下的方式进行:
(其实这种方式可以先生成一个空的Native C++项目看一下文件夹结构和内容,新添加多数情况下可以直接拷贝模板过来,但是用C++和C写的so文件的语法和格式也是有一些出入的)
- 先在src->main下构建cpp文件夹,以及文件夹下的main.c, CmakeLists.txt,空置
- apk文件夹右键:link c++ project with gradle,路径选择刚刚新建的那个CmakeList.txt。
-
cmake_minimum_required(VERSION 3.4.1)
add_library(
# Specifies the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
main.c)
-
点击右上角小象:
-
然后就可以书写main.c的代码了
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
return (*env)->NewStringUTF(env, "hello from c++ language");
}
JNIEXPORT jint JNICALL Java_com_example_myapplication_MainActivity_sum(JNIEnv *env, jobject thiz, jint num1, jint num2){
return num1+num2;
}
在MainActivity中进行native-lib的调用就可以完成了
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("from native-lib", stringFromJNI());
Log.i("from native-lib", "sum result: " + sum(10, 15));
}
public native String stringFromJNI();
public native int sum(int num1, int num2);
}
本文的主要来源:
https://www.52pojie.cn/thread-706568-1-1.html
https://blog.csdn.net/qycc3391/article/details/114241225
下面是我在研究ndk-build的时候成功生成so文件但是闪退的过程,希望有大佬帮我看看哪里出了什么问题:
File->Project Structure
-
按照生成的.h文件书写自己的c语言文件,命名为java调用的library的名字。然后在java同级目录下创建一个jni文件夹。将c和h文件放进去
-
Android.mk文件书写:
大家都知道在Linux下编辑经常要写一个Makefile文件, 可以把这个Makefile文件理解成一个编译配置文件,它保存着如何编译的配置信息,即指导编译器如何来编译程序,并决定编译的结果是什么。而在Android下的Android.mk文件也是类型的功能,顾名思义,从名字上就可以猜测得到,Android.mk文件是针对Android的Makefile文件.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次。你可以在每一个Android.mk file中定义一个或多个模块,你也可以在几个模块中使用同一个源代码文件。编译系统为你处理许多细节问题。
- 在在控制台中,进入到工程的jni目录下,然后输入ndk-build(如下所示),不出问题即可编译成功(但是在在入口调用会闪退,问题来源暂不明朗)。