Android Studio NDK使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tyzlmjj/article/details/50725281

转载请标明出处:
http://blog.csdn.net/tyzlmjj/article/details/50725281
本文出自:【M家杰的博客】


2016-3-27更新
目前Android Studio使用NDK的最佳方式看这里

以下为原文

环境搭建

  • 安装NDK

SDK工具里面已经提供了NDK的下载,以后不需要再去官网找地址自己下载了。
注意:用这个下载的时候可能遇到第一次下载完但是安装不成功的情况,再勾选一次就能完成安装了,我两台电脑都是点两次才成功!
环境搭建


  • 为module添加NDK

下载完的NDK就在原来的SDK目录下
环境搭建


  • 修改配置文件

Project的build.gradle文件中修改如下

……
dependencies {
  //注释掉这个 
  //classpath 'com.android.tools.build:gradle:1.5.0'
  //修改成如下
    classpath 'com.android.tools.build:gradle-experimental:0.4.0'  
}
……


Module的build.gradle文件中修改,这个修改比较多,我贴下修改前后的2份文件方便对比。
注意:不同于Eclipse,没有什么Android.mk文件,NDK的配置都在这里完成,具体看官方文档

新建项目自动生成的:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.mjj.jnitest"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

修改后的文件:

apply plugin: 'com.android.model.application'
model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.2"

        defaultConfig.with {
            applicationId = "com.mjj.jnitest"
            minSdkVersion.apiLevel = 15
            targetSdkVersion.apiLevel = 23

            versionCode = 1
            versionName = "1.0"
        }
    }

    android.ndk {
        moduleName = "jni-Demo"
        ldLibs.addAll(["android", "log"])
    }
    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles.add(file('proguard-rules.txt'))
        }
    }
    android.productFlavors {
        create("arm") {
            ndk.abiFilters.add("armeabi")
        }
        create("arm7") {
            ndk.abiFilters.add("armeabi-v7a")
        }
        create("arm8") {
            ndk.abiFilters.add("arm64-v8a")
        }
        create("x86") {
            ndk.abiFilters.add("x86")
        }
        create("x86-64") {
            ndk.abiFilters.add("x86_64")
        }
        create("mips") {
            ndk.abiFilters.add("mips")
        }
        create("mips-64") {
            ndk.abiFilters.add("mips64")
        }
        create("all")
    }
}


  • 创建jni文件夹

上面的都完成之后,这个项目就可以使用NDK了。首先创建一个存放本地代码的目录,目录就叫jni,默认位置../项目/src/main/jni
环境搭建


编译头文件

开始使用NDK开发写代码之前,还需要了解一点基本的命令,比如生成头文件的命令,这在开发中使用频率还是比较高的。

  • 基本命令

生成.h头文件的命令, -jni是默认的,不写也可以

javah -jni [包名.类名]

例:

javah -jni com.test.MyClass


  • 编码问题

国内基本都用UTF-8编码,在windows下一般默认是GBK,编译的时候会出错,这个时候就要声明下编码,使用-encoding

javah -encoding UTF-8 com.test.MyClass


  • 在Android Studio工程中使用

首先CD到放Java包的目录下,一般的目录../项目名/src/main/java
按标准的目录格式,生成的头文件要放到jni文件夹中,使用修饰符-d

javah -d ../jni com.test.MyClass

按上面这样生成头文件比较方便,也可以加上编码声明:

javah -encoding UTF-8 -d ../jni com.test.MyClass

简单例子

官方的例子在Android Studio中可以很方便的导入,建议看看官方例子。下面是我写的一个简单的例子。

新建一个项目,里面只有一个ManActivity类和一个对应的布局文件。

在ManActivity中声明一个本地方法并加载本地库,代码如下:

public class MainActivity extends AppCompatActivity {

    //加载library
    static {
        System.loadLibrary("jni-Demo");
    }

    //本地方法
    private native String sayHello();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = (TextView) findViewById(R.id.textView);
        //使用本地方法
        textView.setText(sayHello());
    }
}

注意:上面代码中System.loadLibrary("jni-Demo")这一段中jni-Demo这个名字是在module的Build.gradle的android.ndk标签中定义好的

然后用命令行CD到java目录,生成头文件,我的包名是:com.mjj.jnitest
所以命令是这样的:

javah -encoding UTF-8 -d ../jni com.mjj.jnitest.MainActivity

成功之后就会在jni目录生成一个.h文件。

然后在jni目录新建一个C++文件,导入刚才的头文件并且把头文件里的方法复制过来修改下,代码如下:

#include "com_mjj_jnitest_MainActivity.h"
#include <jni.h>

JNIEXPORT jstring JNICALL Java_com_mjj_jnitest_MainActivity_sayHello
        (JNIEnv *env, jobject jobject1)
{
    return env->NewStringUTF("这是一段本地方法返回的字符串!");
}

到这里就完成了一个简单的例子。其实在这个例子中,你不生成头文件也没关系,创建一个C++文件,自己手动写这个方法名就可以了。


在本地代码中打印Log

先在build.gradle的android.ndk标签中添加依赖

android.ndk {
   …… 
   ldLibs.addAll(["android", "log"])
}

然后在C文件中添加代码如下:

//导入日志头文件
#include <android/log.h>
//修改日志tag中的值
#define LOG_TAG "asd"
//日志显示的等级
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

上面的代码主要是简化使用时的操作,可以很简单的使用:

LOGI("打印一个整型:%d",22);
展开阅读全文

没有更多推荐了,返回首页