Android Studio 中 JNI编程 与 NDK开发

本文以一个简单的Android App来说明如何实现在Java中调用C函数,以及如何在Android Studio中使用NDK进行开发

APP功能:在Java代码中调用C语言编写的两数之和函数计算出结果,然后将结果显示出来。

一、安装和配置 NDK 开发环境

请参考下面文章

https://blog.csdn.net/u012851408/article/details/103474412

二、创建Android项目

JniTest.java的内容如下:

package com.example.jnitest;

public class JniTest {
    private static final String TAG = "JniTest";

    static {
        System.loadLibrary("SumLib");
    }

    public native int sum(int x, int y);

}

注意:在Android Studio Java代码中写native本地方法的时候会提示红色异常,解决方法是在File->Settings->Editor->Code Style->Inspections->Android中找到Missing JNI funciotn ,把对钩去掉然后点击Apply即可

MainActivity代码如下:

package com.example.jnitest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
    private EditText value1,value2;
    private TextView result;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        value1 = findViewById(R.id.value1);
        value2 = findViewById(R.id.value2);
        result = findViewById(R.id.result);
        Button equal = findViewById(R.id.equal);

        equal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String v1 = value1.getText().toString();
                String v2 = value2.getText().toString();
                if(v1.isEmpty() || v2.isEmpty()){
                    Toast.makeText(MainActivity.this,"Please input number1 and number2 first!",Toast.LENGTH_LONG).show();
                }else{
                    int data1 = Integer.parseInt(v1);
                    int data2 = Integer.parseInt(v2);
                    JniTest jniTest = new JniTest();
                    result.setText(""+jniTest.sum(data1,data2));
                }
            }
        });
    }
}

三、生成本地方法原型

1、创建jni目录

在项目右键,选择New->Folder->JNI Folder,在弹出的对话框中选择Finish就会在项目的app/src/main/目录下创建jni目录。

2、生成本地方法原型.h文件

可以通过命令行生成.h文件也可以通过配置Android Studio通过编译生成。

命令行方法:

先进入的项目的app/src/main/java目录然后执行下面命令,就会在当前目录下生成com_example_jnitest_JniTest.h文件,最后把com_example_jnitest_JniTest.h文件移动到app/src/main/jni目录即可

javah -jni com.example.jnitest.JniTest

通过Android Studio的方法:

点击File->Settings->Tools->External Tools 打开外部工具配置页面,点击"+"选项新建一个工具。

Name和Description:自己命名,如javah。

Program:系统中javah程序的路径

Arguments:-classpath . -jni -d $ModuleFileDir$/src/main/jni $FileClass$

Working directory:$ModuleFileDir$/src/main/java

填写完成后点击OK就会保存并创建工具。然后右击JniTest.java,在菜单中选择External Tools->javah就可以快速的生成com_example_jnitest_JniTest.h文件并放到jni目录

com_example_jnitest_JniTest.h文件内容如下

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

#ifndef _Included_com_example_jnitest_JniTest
#define _Included_com_example_jnitest_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jnitest_JniTest
 * Method:    sum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_jnitest_JniTest_sum
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

四、编写C代码

在jni目录下新建一个c语言源码,这里叫做sumlib.c。然后实现com_example_jnitest_JniTest.h文件中所定义的函数

在函数体中实现传入参数两数之和的运算,然后回调Java代码中的CalculationResult(String result)方法将结果反馈给java程序

代码如下:

#include <com_example_jnitest_JniTest.h>

#include <android/log.h>
#define LOG_TAG "Syste.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG ,  LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO ,  LOG_TAG, __VA_ARGS__)

/*
 * Class:     com_example_jnitest_JniTest
 * Method:    sum
 * Signature: (II)I
 */

JNIEXPORT jint JNICALL Java_com_example_jnitest_JniTest_sum
  (JNIEnv * env, jobject object, jint x, jint y) {
    LOGI("Native method is called!");
    return x + y;
}

五、创建Android.mk和Application.mk文件

mk文件用于告诉ndk-build该如何编译C源码,在jni目录下依次创建Android.mk和Application.mk文件

Android.mk文件内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := SumLib
LOCAL_SRC_FILES := \
        sum.c

#Add Log
LOCAL_LDLIBS := -lm -llog

include $(BUILD_SHARED_LIBRARY)

Application.mk文件内容如下:

APP_MODULES := SumLib
APP_ABI := all

六、编译C程序生成

我们需要通过Android Studio调用ndb-build来编译,首先需要在项目module的build.gradle里,android.defaulConfig中加入ndk和sourceSet.main内容配置,如下:

ndk{
    moduleName "SumLib"
    ldLibs "log"
}
sourceSets.main{
    jni.srcDirs = []
    jniLibs.srcDirs "src/main/libs"
}

C程序的编译有两种方法

第一种方法:可以使用ndk-build命令编译或外部工具方便编译

外部工具添加方法:点击File->Setting->Tools->External Tools 打开外部工具配置页面,点击"+"选项新建一个工具。

Name和Description自己命名,我填的ndk-build。

Program是你系统中ndk-build程序的路径,Arguments填:不填

Working directory填:$ProjectFileDir$/app/src/main

填写完成后点击OK就会保存创建工具。然后在任意地方右击在菜单中选择External Tools->ndk-build即可编译C源码,成功后就可看见创建了libs目录,里面包含了不同平台下的动态库文件

用同样的方法可以添加一个清除C库的选项如下

Name和Description自己命名,我填的ndk-build clean。

Program是你系统中ndk-build程序的路径,Arguments填:clean

Working directory填:$ProjectFileDir$/app/src/main

第二种方法:可以将NDK Build添加到build.gradle中这样每次编译app的时候就会默认编译C库,而且这样的话在写C代码的时候Android Studio会和Java代码一样有提示补全代码功能。添加方法如下:

1.在File->Project Structrue->SDK Location->Android NDK location中设置NDK的路径

2.在Android视图下,项目名右键->Link C++ Project with Gradle

Build System 选ndk-build

Project Path 填:项目中Android.mk的绝对路径

点击OK 后你就会在module build.gradle的 android选项中看到

externalNativeBuild {
    ndkBuild {
        path 'src/main/jni/Android.mk'
    }
}

七、编译项目生成apk,安装到设备,效果如下

八、程序源码

https://download.csdn.net/download/u012851408/12024458

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值