简单的NDK开发

配置NDK环境,进行简单Native开发

NDK下载
环境变量配置

为ndk和jdk配置环境目录保证javah命令和ndk-build命令可以直接在命令行使用。

为AndroidStudio工程配置NDK路径

打开local.properties文件,添加ndk目录:

sdk.dir=C\:\\Users\\realhe\\AppData\\Local\\Android\\Sdk
ndk.dir=D\:\\ndk\\android-ndk-r10c

打开build.gradle,在defaultConfig中添加ndk{}:

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.realhe.myapplication"
        minSdkVersion 19
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
      //配置处如下
        ndk{
            moduleName "test"            //生成的so名字
            abiFilters "armeabi", "armeabi-v7a", "x86"    //输出指定三种abi体系结构下的so库
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        //此处为调试配置,可选项
            ndk {
                debuggable = true
            }
        }
        debug {
            debuggable = true
        //此处为调试配置,可选项
            jniDebuggable = true
        }
    }

}

保存后可能发生

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin

解决方法为在gradle.properties 中添加一行:

android.useDeprecatedNdk=true
JNI初步
创建文件夹

new > Folder >JNI Folder创建jni文件夹,默认目录为

app/src/main/jni

新建一个使用jni的类
public class Test {
    static {
        System.loadLibrary("test");//需要与前面的so文件名保持一致
    }
    public native String get();
    public native void set(String str);
    public native int getToken(int token);
}
导出Test类的native方法对应的头文件:
C:\Users\realhe\AndroidStudioProjects\MyApplication>
javah -classpath 
app\build\intermediates\classes\debug\ 
-d 
app\src\main\jni 
com.example.realhe.myapplication.Test

上面参数的含义依次是javah命令,classpath路径

.class文件所在的文件夹app\build\intermediates\classes\debug\

-d:输出.h到目标文件夹app\src\main\jni (即前面我们制定的默认jni文件夹)

com.example.realhe.myapplication.Test:含有native方法的类

注意这个地方一定要在项目根目录下使用,而不能切换到 Test类的.class文件所在目录直接使用

之后可以看到生成的头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_realhe_myapplication_Test */

#ifndef _Included_com_example_realhe_myapplication_Test
#define _Included_com_example_realhe_myapplication_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    get
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_realhe_myapplication_Test_get
  (JNIEnv *, jobject);

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    set
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_example_realhe_myapplication_Test_set
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    getToken
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_example_realhe_myapplication_Test_getToken
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif
实现头文件中的方法

在默认的JNI文件夹中新建一个test.c文件,包含上述头文件并实现其中的方法:

//
// Created by realhe on 2016/7/18.
//
#include "com_example_realhe_myapplication_Test.h"
static int count = 0;
JNIEXPORT jstring JNICALL Java_com_example_realhe_myapplication_Test_get
        (JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env,"This is a test for NDK!");
}

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    set
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_example_realhe_myapplication_Test_set
(JNIEnv *env, jobject ibj, jstring jsr){}

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    getToken
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_example_realhe_myapplication_Test_getToken
        (JNIEnv *env, jobject obj, jint jinvar){
    return count++;
}

注意:此处由于ndk的一个BUG,在编译单个.c文件时会报错:

com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:ndkandroid-ndk-r10ndk-build.cmd'' finished with non-zero exit value 2

解决方法为在同级目录下增加一个empty.c的空文件即可。

使用Native方法

在MainActivity中使用Nativce方法设置TextViewText:

TextView textView = (TextView)findViewById(R.id.tv_hello);
Test test = new Test();
String content = test.get();
for (int i = 0;i<10;i++){
  content += ("\n("+ test.getToken(1) + ")");
}
textView.setText(content);

最后效果如下:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏蔡鹏的专栏

Dubbo API形式 简单入门

4203
来自专栏开发技术

从源码来理解slf4j的绑定,以及logback对配置文件的加载

  项目中的日志系统使用的是slf4j + logback。slf4j作为一个简单日志门面,为各种loging APIs(像java.util.logging,...

1944
来自专栏Java 源码分析

SpringBoot 笔记(十):错误处理

2907
来自专栏乐沙弥的世界

使用 runcluvfy 校验Oracle RAC安装环境

--*****************************************

1082
来自专栏C/C++基础

CMake简介及使用实例

CMake是一个跨平台的建构系统的工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的构建文档makefile或者project文件,描...

1612
来自专栏大大的微笑

RMI

RMI定义:     RMI即远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个j...

2675
来自专栏小勇DW3

Spring的原理性总结

Bean的生命过程可以借鉴Servlet的生命过程,了解其生命过程对于不管是思想还是以后的使用都很有帮助;

1.8K5
来自专栏Android 研究

APK安装流程详解6——PackageManagerService启动前奏

由于在后面讲解PackageManager流程启动的时候会 涉及到Setting类,我们就先预热下 Settings.java源码地址

1832
来自专栏Ryan Miao

在dropwizard中使用feign,使用hystrix

前言 用惯了spring全家桶之后,试试dropwizard的Hello World也别有一帆风味。为了增强对外访问API的能力,需要引入open feign...

40712
来自专栏菩提树下的杨过

linq学习笔记(二)

试用了几天linq,感觉确实方便,而且生成的sql也还不错,下面是几点体会 1.几种常见的等效select写法 var s = from c in ctx.T...

19110

扫码关注云+社区

领取腾讯云代金券