赞
踩
注意:可以直接翻到后面的## 2021年新增
部分看起了,当然前面看看也挺好,哈哈。
平台:windows
IDE :Android Studio
下载好ndk:下载地址 https://developer.android.com/ndk/downloads/index.html
第1步:新建一个Android Studio 工程 JniHelloWorld。新建一个MyJni.java文件。
MyJni.java
public class MyJni {
static {
System.loadLibrary("MyJni");
}
public native static String getString();
}
第2步:然后点击一下 make project 会在app的build目录下面生成.class文件。
第3步,在app/src/main文件夹下新建一个jni文件夹,然后打开Android Studio的终端,cd到这个目录,然后输入下面的指令
javah -jni -classpath D:\github\JniHelloWorld\app\build\intermediates\classes\debug com.brotherd.jnihelloworld.MyJni
就会在这个jni文件夹下生成一个.h文件,com_brotherd_jnihelloworld_MyJni.h,文件内容如下。
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_brotherd_jnihelloworld_MyJni */ #ifndef _Included_com_brotherd_jnihelloworld_MyJni #define _Included_com_brotherd_jnihelloworld_MyJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_brotherd_jnihelloworld_MyJni * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_brotherd_jnihelloworld_MyJni_getString (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
在scr/main/jni
目录下新建一个c/c++source file ,取名test.c 实现上面.h文件中的方法。
#include "jni.h"
#include "com_brotherd_jnihelloworld_MyJni.h"
JNIEXPORT jstring JNICALL Java_com_brotherd_jnihelloworld_MyJni_getString
(JNIEnv *env, jclass jz){
return (*env)->NewStringUTF(env,"this is the first time for me to use jni");
}
接着在jni文件夹下新建Android.mk和Application.mk文件。
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyJni
LOCAL_SRC_FILES := Test.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
第4步,关联下载好的ndk包,我的解压好的路径是C:\android-ndk-r14b
然后在终端进入到jni目录,输入指令 ndk-build,就会生成相应的so文件。
第5步,调用so文件。
在app的bulid文件中加入如下代码,然后build project
android {
...
sourceSets {
main() {
jniLibs.srcDirs = ['src/main/libs']
jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
}
}
}
在MainActivity中调用
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
textView.setText(MyJni.getString());
}
}
运行效果图
平台:mac
IDE :Android Studio 4.2.1
首先确保已经安装了CMake工具,没有安装的安装一下。
然后新建一个项目,选择Native C++
,点击Next
输入项目名称,JniHelloWorld1,语言这里选择了Kotlin。Next
C++我们选择 Toolchain Default 这一项就可以,然后点击finish。
创建好的项目结构如下所示:
我们可以看到这里有一个cpp文件夹,文件夹下面有两个文件。我们先运行看一下效果。
创建项目时,默认的MainActivity
package com.example.jnihellowrold1 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.TextView import com.example.jnihellowrold1.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 调用一个native方法来获取字符串。 binding.sampleText.text = stringFromJNI() } /** * native方法,由 'native-lib' 这个native库来实现。native-lib会打包到应用中。 */ external fun stringFromJNI(): String companion object { // 静态方法,在加载MainActivity类的时候,会加载'native-lib'库。 init { System.loadLibrary("native-lib") } } }
我们在build文件夹下可以看到生成的so文件。有趣的是真正生成的so的命名是libnative-lib.so
。
我们看下native-lib.cpp
文件。
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jnihellowrold1_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
//返回一个字符串 Hello from C++
return env->NewStringUTF(hello.c_str());
}
我们什么都没有做,我们就生成了libnative-lib.so
文件并实现了调用native方法,这一切是谁帮我们做的呢?显然是CMake了。我们看一下CMakeLists.txt
这个文件里面的内容。
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # 设置用来构建native library所需CMake的最小版本。 cmake_minimum_required(VERSION 3.10.2) # 声明项目名称。 project("jnihellowrold1") # 创建并命名库,将库设置为静态的或者共享的,并提供源代码文件的相对路径。 # 你可以定义多个库,CMake会为你构建它们。 # Gradle会自动将共享库打包到你的apk里面。 add_library( # 设置库的名称 native-lib # 将库设置为共享的 SHARED # 提供源代码文件(可以是多个文件)的相对路径。 native-lib.cpp ) # 搜索指定的预构建库并将其路径存储为变量。 # 因为CMake会在搜索路径上默认包含系统库,你只需要指定你想添加的公共的NDK库。 # 在完成构建之前CMake会验证这些库是否存在。 find_library( # 设置路径变量的名称。 log-lib # 指定你想让CMake定位的NDK库的名称。 log ) # 指定CMake应该链接到目标库的库。 # 你可以链接多个库,例如你在这个构建脚本中定义的库,预编译的三方库,或者系统库。 target_link_libraries( # 指定目标库 native-lib # 将目标库链接到NDK中包含的日志库。 ${log-lib} )
那么CMakeLists.txt
是怎么执行的呢,显然是在gradle.build
文件中。
app/build.gradle文件精简版
//... android { compileSdkVersion 30 defaultConfig { applicationId "com.example.jnihellowrold1" minSdkVersion 21 targetSdkVersion 30 versionCode 1 versionName "1.0" //注释1处, externalNativeBuild { cmake { cppFlags '' } } } //... //注释2处,指定cmake文件所在的路径 externalNativeBuild { cmake { path file('src/main/cpp/CMakeLists.txt') version '3.10.2' } } }
参考链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。