java - 在 Android JNI/NDK 代码中从 C++ 函数调用 C 函数

标签 java android c++ c android-ndk

我正在尝试从 NDKTest.c 文件调用 stringFromJNI2(env, obj) 函数。

这是 NDKTest.c 文件的代码:

#include <string.h>

#include <stdio.h>
#include <jni.h>
#include <limits.h>

JNIEXPORT jstring JNICALL
Java_com_test_ndk_NDKTest_stringFromJNI2( JNIEnv *env,
                                              jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
  #if defined(__ARM_PCS_VFP)
    #define ABI "armeabi-v7a/NEON (hard-float)"
  #else
    #define ABI "armeabi-v7a/NEON"
  #endif
#else
  #if defined(__ARM_PCS_VFP)
    #define ABI "armeabi-v7a (hard-float)"
  #else
    #define ABI "armeabi-v7a"
  #endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif

return (*env)->NewStringUTF(env, "Hello from JNI2 !  Compiled with ABI " ABI ".");

}

这是 NDKTest.h 文件的代码:

#ifndef NDKTEST_H_
#define NDKTEST_H_

#include <jni.h>
#include <string>

const std::allocator<char> & stringFromJNI2(JNIEnv *env, jobject thiz);

#endif

这是 TestNDK.cpp 文件的代码:

#include <string.h>
#include <jni.h>

#include <string>
#include <jni.h>

#include "NDKTest.h"

extern "C" {
    stringFromJNI2(JNIEnv *env, jobject obj);
}

JNIEXPORT jstring JNICALL
Java_com_test_ndk_TestNDK_main(JNIEnv *env, jobject obj) {
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#endif
    //std::string hello("Hello from JNI !  Compiled with ABI " ABI ".");
    std::string hello(stringFromJNI2(env, obj));
    return env->NewStringUTF(hello.c_str());
}

这是 TestNDK.java 文件的代码:

package com.test.ndk;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class TestNDK extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /* Retrieve our TextView and set its content.
     * the text is retrieved by calling a native
     * function.
     */
    setContentView(R.layout.activity_hello_jni);
    TextView tv = (TextView)findViewById(R.id.hello_textview);
    tv.setText( main() );

    public native String main();

    static {
        //System.loadLibrary("main");
        System.loadLibrary("TestNDK");
    }
}

这是 CMakeLists.txt 文件中的行:

cmake_minimum_required(VERSION 3.4.1)

add_library(testNDK SHARED
        TestNDK.cpp
        NDKTest.c)

# Include libraries needed for testNDK lib
target_link_libraries(testNDK
                  android
                  log)

这是来自 build.gradle 文件的代码:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.2'
    defaultConfig {
        applicationId 'com.test.ndk'
        minSdkVersion 23
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang'
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
    productFlavors {
        arm7 {
            // in the future, ndk.abiFilter might also work
            ndk {
                abiFilter 'armeabi-v7a'
            }
        }
        arm8 {
            ndk {
                abiFilters 'arm64-v8a'
            }
        }
        arm {
            ndk {
                abiFilter 'armeabi'
            }
        }
        x86 {
            ndk {
                abiFilter 'x86'
            }
        }
        x86_64 {
            ndk {
                abiFilter 'x86_64'
            }
        }
        mips {
            ndk {
                abiFilters 'mips', 'mips64'
            }
        }
        universal {
            ndk {
                abiFilters 'mips', 'mips64', 'x86', 'x86_64'
            }
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.2.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.1'
}

我目前收到以下错误“错误:(10, 1) 错误:C++ 需要所有声明的类型说明符”和“错误:(29, 23) 错误:调用‘stringFromJNI2’不明确”由于到 TestNDK.cpp 中的以下代码行:

stringFromJNI2(JNIEnv *env, jobject obj);

这行代码位于 extern "C"代码块中。我正在尝试从 TestNDK.cpp 文件调用 NDKTest.c 文件中的 stringFromJni2() 函数。我将如何修复我遇到的当前错误并调用 NDKTest.c 文件中的 stringFromJNI2() 函数以显示“Hello from JNI2!使用 ABI 编译”字符串。对此的任何帮助将不胜感激。谢谢。

最佳答案

I'm trying to call the stringFromJni2() function in the NDKTest.c file from the TestNDK.cpp file.

您应该在 NDKTest.h 中声明来自 NDKTest.c 的函数原型(prototype)。所以标题应该是这样的:

#ifndef NDKTEST_H_
#define NDKTEST_H_

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

jstring Java_com_test_ndk_NDKTest_stringFromJNI2(JNIEnv *env, jobject thiz);

#ifdef __cplusplus
}
#endif

#endif

TestNDK.cpp:

#include <jni.h>

#include "NDKTest.h"

#ifdef __cplusplus
extern "C" {
#endif

// remove this declaration
// stringFromJNI2(JNIEnv *env, jobject obj);

JNIEXPORT jstring JNICALL
Java_com_test_ndk_TestNDK_main(JNIEnv *env, jobject obj) {
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#endif
    return Java_com_test_ndk_NDKTest_stringFromJNI2(env, obj);
}

#ifdef __cplusplus
}
#endif

TestNDK.java:

// the library name has to be the same
// as you defined in CMakeLists.txt
static {
    System.loadLibrary("testNDK");
}

关于java - 在 Android JNI/NDK 代码中从 C++ 函数调用 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43327690/

相关文章:

java - 按值传递(StringBuilder 与 String)

android - Espresso,使用登录屏幕测试快乐路径

java - 无法从 AdapterView 转换为自定义适配器?

c++ - 将数据从 .cpp 文件传递​​到 Objective c ViewController

c++ - 这个程序的输出怎么会变成 12?

java - 通过Netty发送TCP数据包,Netty是将数据分成不同的数据包?

用于远程IP(主机)的Java RMI

java - JUNG 沿边缘的动画图像

android - HTML5 中的应用程序缓存在 Android PhoneGap 应用程序中不起作用

c++ - 在 for 循环中添加 "time interval"