Android Studio 3.4.1
JRE: 1.8.0_152-release-1343-b01 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 7 6.1
一、环境准备:NDK(针对windows机器)
设置好环境变量,不知道就百度一下;android SDK已经自带ndk-bundle了,对应的目录就是Android/sdk/ndk-bundle。先确保ndk-build命令能运行,打开CMD窗口,如果能看到以下内容,说明已经配置成功。
再增加环境变量 NDK_PROJECT_PATH,就是ndk-bundle的路径,我的路径是D:\android-ndk-r12b-windows-x86_64\android-ndk-r12b
Path里面添加一个系统变量,指向本地ndk目录。
%NDK_PROJECT_PATH%;
以下是我的环境变量,可以参考下:
Path
.;%JAVA_HOME%\bin;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;d:\Program Files\Git\cmd;C:\Program Files\TortoiseGit\bin;D:\android-sdk_r24.4.1-windows\android-sdk-windows\tools;D:\android-sdk_r24.4.1-windows\android-sdk-windows\platform-tools;d:\Program Files (x86)\MATLAB\MATLAB Compiler Runtime\v80\runtime\win32;C:\Program Files (x86)\EmEditor;D:\android-ndk-r12b-windows-x86_64\android-ndk-r12b;%NDK_PROJECT_PATH%;
CLASSPATH
.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
JAVA_HOME
C:\Program Files\Java\jdk-12.0.1
Android studio 路径设置:
Android studio 命令设置:
当然可以通过命令行的方式生成头文件,javah -jni 之类的,但是android studio已经简化这个工作了,配置一下,只需要右键生成.h文件即可;请看下面,配置工作本质上也是调用javah命令。
打开android studio的设置窗口file->setting,选择External Tools -> 新建(+号)
增加javah
$JDKPath$\bin\javah.exe
$FileClass$
$ModuleFileDir$\src\main\java
填上以下内容。点击右边的Insert Macros有惊喜哦^^
增加一个ndk-build
D:\android-ndk-r12b-windows-x86_64\android-ndk-r12b\ndk-build.cmd
$ProjectFileDir$
二、新建Android studio工程编写软件
新建完编译一下,编译成功
三、编写一个包含native方法的Java,并生成.h
新建Java文件
写一个native 方法
package com.yk.demo_jni_2;
public class JavaJNI {
//native方法
public static native String sayHello();
}
选择Java文件右键,生成.h
新建一个jni目录
将.h文件移到目录
三、在这个目录创建实现C或者C++文件
新建.c文件,实现.h里的函数,这里函数并返回字符串,注意要修改函数的参数名字
注意:C和C++有点区别,
对于XXX.c:JNI 函数调用由“(*env)->”作前缀,目的是为了取出函数指针所引用的值。
(*env)->NewStringUTF(env,"HelloJNI!");
对于XXX.cpp:JNIEnv 类拥有处理函数指针查找的内联成员函数。
env->NewStringUTF("HelloJNI!");
可以发现,C或者C++的实现很类似,但是它们对env的操作方式有所不同,因此使用C和C++来实现同一个JNI方法,它们的区别主要集中在对env的操作上,其他都是类似的。
---------------------
四、配置Android.mk和Application.mk文件
新建两个文件 Application.mk、Android.mk
Application.mk 可以定义得很简单
APP_BUILD_SCRIPT:=./Android.mk
APP_ABI := armeabi armeabi-v7a x86
意思是输出armeabi, armeabi-v7a, x86三种架构的so
Android.mk内容多了一点点
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni_hello
LOCAL_SRC_FILES := jni_sayHello.c
include $(BUILD_SHARED_LIBRARY)
android官方描述:Android.mk
前面两行和最后一行是固定的;
LOCAL_PATH是定义的开始,用于查找源文件;
jni_hello就是要输出的so名字,当然最终会是libjni_hello.so;
LOCAL_SRC_FILES指向要编译的源文件;
四、生成.so
只需要在jni这个目录右键,选择ndk-build命令即可(上面配置的)。在你的项目中就会成功输出so库了。
会在项目根目录生成一个obj目录,里面就存放着生成的so。
如果之前生成出错,记得把obj目录清空一下,把错误解决后重新ndk-build。
我这里右键ndk-build有错误,提示没找到Android.mk 可能是哪里没设置好
解决办法:
那就用Android自带的命令框,手动编译so
进入到jni所在的目录,ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk
成功后就会生成.so文件
、
五、测试生成的.so
很多教程比较旧,都说需要在 gradle.properties 文件里加的配置:android.useDeprecatedNdk=true
以上配置在Android Studio 3 之后就废弃了(不需要加上)
修改main
运行时候,如下错误说明没有所在lib的路径:
在app下的build.gradle里增加库的路径,根据自己的路径设置
修改MainActivity,一种是直接调用,另一种是通过类调用,查看log都是OK的
还人说需要设置支持的SO库架构,我测不设置也可以在手机上运行的
defaultConfig {
applicationId "com.yikuncom.yk5200"
minSdkVersion 21
targetSdkVersion 19
versionCode 2
versionName "YKS_01.01_01.01_190510"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
// 设置支持的SO库架构
abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
}
六、JNI里的打印log
在jni里打印log,需要在Android.mk 添加
LOCAL_LDLIBS := -lm -llog
添加打印信息,重新生成.so
使用USB连接设备,adb shell
logcat |gret "hello" //查看打印信息