搭建环境
sdk 路径设置 sdktools下载
NDK 配置 在 系统path中加入
判断安装好标志 在terminal输入ndk-build命令
在项目project structure中如下
java环境
报错 javah 不是内部命令 环境没配置好
填写系统环境path路径的时候 在编辑文本中看一眼,或者在AS客户端的terminal中echo %path% 确定对不对,中间分号间隔
创建工程
1.创建一个工程,名字随便,
eg. TestDemo1,勾选include c++;空活动;
下一步,直到最后勾选Expections surport, runtime(非必须);
2.创建
建立一个jniutil.java
任意目录下 创建java类 (本文目录为TestDemo1\app\src\main\java)
Demo1.java
package com.example.tsing.testdemo1;
/**
* Created by Tsing on 10/19/2017.
*/
public class Demo1 {
static {
System.loadLibrary("testdemo1");
}
public static native String sayHello();
}
注意 static中System.loadLibrary(“testdemo1”); 必须加上这句话,以后才可以引用
testdemo1是后来的so文件名称,必须一致
然后Clean Project,Rebuild Project,之后,你就能在项目的路径:app\src\main\java\看到 com.example.tsing.testdemo1.Demo1.class(或 com目录下)
2.生成h文件
进入AS的terminal cd 目录地址 到com上层目录截至 (防止出现找不到路径), javah 文件名 不可以带class(最终生成h文件就是在这个目录)
F:\AndroidStudioProjects\TestDemo1>cd app\src\main\java
F:\AndroidStudioProjects\TestDemo1\app\src\main\java
>javah -jni com.example.tsing.testdemo1.Demo1
3.以上操作如果没有问题的话,就会生成h文件
com_example_tsing_testdemo1_Demo1.h文件。在项目的src/main下面建立一个jni文件夹,将生成的com_example_tsing_testdemo1_Demo1.h文件拷贝进去。
在jni文件夹里面,新建一个与.h对应的.c文件,名字可以随便,我取得名字为:main.c,加入以下代码:(确保与h中声明函数相对应,否则会报错)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "com_example_tsing_testdemo1_Demo1.h"
/* Header for class com_example_tsing_testdemo1_Demo1 */
/*
* Class: com_example_tsing_testdemo1_Demo1
* Method: sayHello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_tsing_testdemo1_Demo1_sayHello
(JNIEnv *env,jclass jclass){
return (*env)->NewStringUTF(env,"JNi success");
}
4、Jni类的配置及引用
在项目app下的build.gradle下面配置ndk:
在defaultConfig中插入ndk片段
ndk{
moduleName "testdemo1"
//生成的so名字
ldLibs "log","z","m"
abiFilters "armeabi","armeabi-v7a","x86"
//输出指定三种abi体系结构下的so库,目前可有可无。
}
5在gradle.properties加入配置
android.useDeprecatedNdk=true
问题 make project 此时如果生成so文件,在app\build\intermediates\ndk->debug->lib下,如果此时没有,说明ndk配置有误,尝试ndk手工编译
ndk-build命令编译
用ndk-build 生成“so”文件,我们还需要在“jni”目录中创建两个文件,分别是Android.mk和Application.mk。下面分别看看他们的具体实现!
Application.mk,这个文件用来配置编译平台相关内容,我们最常用的估计只是APP_ABI字段,它用来指定我们需要基于哪些CPU架构的.so文件,当然你可以配置多个平台。下面指定了两个平台。
APP_ABI := armeabi armeabi-v7a
Android.mk,文件用来指定源码编译的配置信息,例如工作目录,编译模块的名称,参与编译的文件等。
include $(CLEAR_VARS)
LOCAL_MODULE := calculate_jni
LOCAL_SRC_FILES := cn_xinxing_jnitest_CalculateUtils.cpp
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:设置工作目录,而my-dir则会返回Android.mk文件所在的目录。
CLEAR——VARS:清除几乎所有以LOCAL开头的变量(不包括LOCAL_PATH)。
LOCAL_MODULE:指定生成动态库名。
LOCAL_SRC_FILES:用来指定生成动态库的源文件 。
BUILD_SHARED_LIBRARY:作用是指定生成的静态库或者共享库在运行时依赖的共享库模块列表。
按照上面的步骤,创建并输入相应的内容后,我们就可以生成“so”文件了。 打开Terminal,cd到工程的“src/main/jni”目录,输入“ndk-build”命令后,回车,如果你看到下面的截图,那就编译成功了(如没安装成功,提示无法识别,可利用ndk本机安装位置,输入D:\android-sdk\Sdk\ndk-bundle\ndk-build 命令)
在main目录下建立jniLibs文件夹,将生成的libs文件夹内内容复制到里面,即将so库复制里面,即可在函数中调用
6.在MainActivity中调用:
1.在static中加载库 这步可有可没有
static {
// System.loadLibrary("native-lib");
System.loadLibrary("testdemo1");
}
2.在oncreat代码部分如下,其中Demo1为类,sayhello为其中的方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(Demo1.sayHello());
}
7.工程目录结构
8.工程链接
git项目代码
git地址
git@github.com:ForeverEighteen/TestDemo1.git
9.android studio生成apk在哪?
app/build/outputs/apk
10.jni原理
首先编辑java类 ,static引用 生成的so库,声明相关函数是native。之后利用javah编译生成h文件,在编辑相应的c文件include 这个h文件,在文件中定义相关的函数。最后在MainActivity中就正常可以调用这个函数了。
arm cortex a53架构
问题 include头文件是红色
在app的build.gradle文件中android 下加入
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
问题 新建文件没有被工程包含
修改cmake文件
cmakelists 文件内容如下
add_library( myapplication3
SHARED
src/main/jni/jnitil.c )
find_library( log-lib
log )
target_link_libraries(
myapplication3
${log-lib} )
so引用
修改buiid.gradle,添加.so引用路径
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
android studio nd开发到底要不要自己配置.mk文件
Android Studio 可以配置build.gradle , main/jni文件夹中的c/c++文件会自动打包成so,但是如果有不同模块的文件,要编译出多个so文件,就不知道在gradle文件中咋配置了(可能也可以配置),这时就可以用原来eclipse的写法;
main/jni文件夹按照原来eclipse的方法去写Android.mk和Application.mk,然后在main目录下执行ndk-build命令,该目录下会创建libs目录,里边就是生成的so,将项目配置的jniLibs.srcDirs指向src/main/libs就行;
这时有几个问题,一个是AS会自动重复编译jni中的文件,打包后会多一个没用的so,还有如果用了第三方的so文件会和自己项目的so文件冲突,因为每次ndk-build后都会删除原来文件夹中的其他so文件.
先去掉 defaultConfig中的ndk配置,然后配置 :
sourceSets{
main{
//指定so库的位置,前边的是自己项目的,后边的是第三方的so
jniLibs.srcDirs=[‘src/main/libs’,’libs’]
//禁止 android studio 自动编译
jni.srcDirs=[]
}
}