编译环境
- Win10 64bit 企业版
- Android Studio 1.5
- android-ndk-r10e
Here we go!
新建项目
这里新建一个项目名为FFmpegDemo
的项目(过程略)
声明native方法
在MainActivity
中声明native方法:public native String getStringFromNative();
然后
Build - Make Project
之后可以在FFmpegDemo\app\build\intermediates\classes\debug\com\example\l1\ffmpegdemo
下看到class中间文件生成头文件(.h)
在Android Studio的Terminal中进入项目main目录,并运行下面命令以生成头文件:javah -d jni -classpath E:\Android\AndroidStudioSDK\platforms\android-19\android.jar; E:\Android\AndroidStudioSDK\extras\android\support\v4\android-support-v4.jar; E:\Android\AndroidStudioSDK\extras\android\support\v7\appcompat\libs\android-support-v4.jar; E:\Android\AndroidStudioSDK\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;
-d
:表示新建目录
-classpath
:指定类路径
我这边如果不指定类路径会出现错误:错误: 无法访问android.support.v7.app.AppCompatActivity 找不到android.support.v7.app.AppCompatActivity的类文件
运行完命令后,将会多一个jni目录,并且里面有个头文件(.h)
实现头文件中声明的方法
在jni目录下新建一个.c文件
,用以实现.h头文件
中的声明方法。这里命名为main.c
,并简单的返回字符串。#include "com_example_l1_ffmpegdemo_MainActivity.h" JNIEXPORT jstring JNICALL Java_com_example_l1_ffmpegdemo_MainActivity_getStringFromNative(JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env,"Hello JNI"); }
配置NDK路径和指定动态库名称
在local.properties
增加NDK路径,文件变成:sdk.dir=E:\\Android\\AndroidStudioSDK ndk.dir=E:\\Android\\android-ndk-r10e
此外,还要在
gradle.properties
文件中加入:android.useDeprecatedNdk=true
否则会报错:
Error:Execution failed for task ':app:compileDebugNdk'. > Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
点击
Build - Make Project
可以在FFmpegDemo\app\build\intermediates\ndk\debug\lib\armeabi
下看到libapp.so
文件,这是默认的动态库名称,我们可以在build.gradle(Module:app)
文件里指定动态库名称:android { ... defaultConfig { ... ndk { moduleName "MyLib" //指定生成动态库的名称 } } ... }
重新编译即可看到
libapp.so
变成了libMyLib.so
使用native方法
最后在MainActivity
中增加动态库载入代码就可以调用native
方法啦~public class MainActivity extends AppCompatActivity { //载入动态库 static { System.loadLibrary("MyLib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.my_tv); tv.setText(getStringFromNative()); //调用native方法 } //声明native方法 public native String getStringFromNative(); }
编译运行就可以在屏幕上看到
Hello JNI
啦~~
C语言中输出Logcat?没问题!
要想在C语言实现代码中输出Logcat信息,其实很简单!!
首先,在main.c
中包含#include <android/log.h>
,然后调用__android_log_print()
打印输出。
#include "com_example_l1_ffmpegdemo_MainActivity.h"
#include <android/log.h>
#define TAG "JNI_TAG"
//为了方便调用,将输出宏定义
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_example_l1_ffmpegdemo_MainActivity_getStringFromNative(JNIEnv *env, jobject obj)
{
//输出Logcat
LOGD("Logcat text");
//或像C语言printf()一样
LOGD("%s You are No.%d","Logcat so easy!", 1);
return (*env)->NewStringUTF(env,"Hello JNI");
}
然后,在build.gradle
中增加链接库。
android {
...
defaultConfig {
...
ndk {
moduleName "MyLib" //指定生成动态库的名称
ldLibs "log" //增加链接库
}
}
...
}
重新编译就可以在Logcat窗口看到输出啦~
参考:
Using the NDK with Android* Studio
How to get “printf” messages written in NDK application?