0 写在开头
Android Studio 0.4.2 使用gradle对jni中的代码进行自动编译,很方便,推荐大家使用,下面是我总结的入门教程,包括了模块的配置
1 环境
IDE: Android Studio 0.4.2
SDK:api-19
NDK:android-ndk-r9d(必须是9以上的,我下载的是最新的)
系统:macos
2 新建android项目
那么这一步中ModuleName我没有修改,是默认的app,里面放的是Activity
创建后的项目结构如下图所示
JNIDemo是整个大项目,下面有app模块。
JNIDemo项目有一个根的build.gradle,
app模块内也有一个build.gradle,就是这个模块的编译配置
3 新建个hellojni模块
因为android studio是以模块为概念的,每个模块类似个library
我们新建一个hellojni模块
如下图所示,右击JNIDemo,选择new - Module - Android Library
修改module name为hellojni,勾掉create activity
现在项目有2个模块了
4 创建.h文件
首先在app模块内的MainActivity.java内添加native方法
public class MainActivity extends ActionBarActivity {
public native String hellojni();
}
然后在hellojni模块根目录下新建一个autojavah.sh
内容如下,
其中TargetClassName为MainActivity的完整名
SourceFile为app模块java源代码根目录
TargetPath为hellojni模块jni根目录
#!/bin/sh
export ProjectPath=$(cd "../$(dirname "$1")"; pwd)
export TargetClassName="com.ashqal.jni.MainActivity"
export SourceFile="${ProjectPath}/app/src/main/java"
export TargetPath="${ProjectPath}/hellojni/src/main/jni"
cd "${SourceFile}"
javah -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"
echo -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"
右击autojavah.sh,点run,即可运行生成.h文件
当然需要注意得是,你得提前装个Bash Plugin,创建.sh文件时会自动提醒
运行完后,.h文件就自动生成了
5 新建cpp文件
在hellojni模块jni文件夹内新建hellojni.cpp
#include "com_ashqal_jni_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_ashqal_jni_MainActivity_hellojni
(JNIEnv* env, jobject obj)
{
return env->NewStringUTF( "Hello from JNI ! Compiled with ABI .");
}
示例修改自ndk samples hellojni
6 配置ndk环境
在项目JNIDemo内找到local.properties
接着添加
ndk.dir=/programes/android-ndk-r9d
7 编译hellojni模块
编译hellojni模块很简单,就是按command+b,当然右击hellojni模块,选择make module也行
编译后就在hellojni/build/ndk中生成了如下图所示文件,obj/local/内是4个不同的target,已经生成了.so文件了
模块名叫hellojni,是自动生成的Android.mk文件,下面会提到如何修改默认的module name,如何配置编译依赖库
8 配置app模块,使之依赖hellojni
选择app模块,右击选择open-module-setting,打开项目结构
一次点击下图所示未知,给app模块添加hellojni模块依赖
添加好后
9 loadlibrary
修改app模块内MainActivity
public class MainActivity extends ActionBarActivity {
public native String hellojni();
static
{
System.loadLibrary("hellojni");
}
}
值得注意得时hellojni为之前Android.mk的LOCAL_MODULE名,但是这个Android.mk是自动生成的,跟eclipse中自己写的放在jni下不一样
之前生成的.so文件名为libhellojni.so,那么loadLibrary为hellojni,去掉前面的lib及后面的.so
10 运行测试
在MainActivity的onCreate函数内调用下,写个测试
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
Log.i("MainActivity",hellojni());
}
点击运行,把程序跑起来了
11 配置自动生成的Android.mk
打开hellojni内的build.gradle,在android标签内加入ndk标签
build.gradle
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
defaultConfig {
minSdkVersion 7
targetSdkVersion 16
versionCode 1
versionName "1.0"
}
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
ndk {
moduleName "jnimain"
abiFilters "armeabi", "armeabi-v7a"
}
}
debug {
ndk {
moduleName "jnimain"
abiFilters "armeabi", "armeabi-v7a"
}
}
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
}
可以很清楚的看到,
moudleName即为新的模块名,
abiFilters为需要生成的target
还有一些属性是
stl "stlport_shared"
ldLibs "log", "z", "m"
cFlags "-I/some/include/path"
这些内容来自
http://stackoverflow.com/questions/20674650/how-to-configure-ndk-with-android-gradle-plugin-0-7
里面大神提到的源代码地址我也搜到了,在
https://android.googlesource.com/platform/tools/build/+/c4f572d8dd9664c63a04f48a99b79acfb9513de9/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/NdkConfigDsl.java
我现在修改了moduleName及abiFilters,按command+b,看看新的编译后的结果
可以看到,只生成了2个target,
也让自动生成的Android.mk改变了里面的内容(LOCAL_MODULE为jnimain)
12 结束语
新版的Android Studio还蛮好用的,上面就是我在学习NDK中的步骤总结,希望大家喜欢!
13 Q & A
抽空又看了下回复,给大家集中解决几个问题
1、为什么选择make module之后没有生成ndk文件夹(@ _程序人生_)
新版本的android studio似乎在项目中过滤了这些文件的显示,和debug的apk看不到是一个道理
其实已经生成了,如下图所示
2、Error:Execution failed for task ':jnimain:compileReleaseNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
/programes/android-ndk-r9d/ndk-build NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=/files/maccode/idea/AndroidJNIDemo/jnimain/build/intermediates/ndk/release/Android.mk APP_PLATFORM=android-20 NDK_OUT=/files/maccode/idea/AndroidJNIDemo/jnimain/build/intermediates/ndk/release/obj NDK_LIBS_OUT=/files/maccode/idea/AndroidJNIDemo/jnimain/build/intermediates/ndk/release/lib APP_ABI=armeabi
Error Code:
2
Output:
In file included from /files/maccode/idea/AndroidJNIDemo/jnimain/src/main/jni/jnimain.cpp:1:0:
/files/maccode/idea/AndroidJNIDemo/jnimain/src/main/jni/com_ashqal_app_MainActivity.h:2:17: fatal error: jni.h: No such file or directory
compilation terminated.
make: *** [/files/maccode/idea/AndroidJNIDemo/jnimain/build/intermediates/ndk/release/obj/local/armeabi/objs/jnimain//files/maccode/idea/AndroidJNIDemo/jnimain/src/main/jni/jnimain.o] Error 1
什么?jni.h找不到?
先看下我写的配置
apply plugin: 'com.android.library'
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
defaultConfig {
minSdkVersion 7
targetSdkVersion 20
versionCode 1
versionName "1.0"
}
buildTypes
{
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
ndk {
moduleName "jnimain"
abiFilters "armeabi" //, "armeabi-v7a"
// stl "stlport_shared"
// ldLibs "log", "z", "m"
// cFlags "-I/some/include/path"
}
}
debug {
ndk {
moduleName "jnimain"
abiFilters "armeabi" //, "armeabi-v7a"
}
}
}
}
dependencies {
compile 'com.android.support:appcompat-v7:20.0.0'
}
因为原先的demo时间比较久了,我首先把targetSdkVersion改成了最新的20
后来发现我后来没更新ndk,ndk目录下根本没有android-20的platforms
所以compileSdkVersion和targetSdkVersion改成19就编译通过了