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

Posted

技术标签:

【中文标题】在 Android JNI/NDK 代码中从 C++ 函数调用 C 函数【英文标题】:Calling C Functions From C++ Function In Android JNI/NDK Code 【发布时间】:2017-04-10 15:48:55 【问题描述】:

我正在尝试从 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);

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

【问题讨论】:

【参考方案1】:

我正在尝试从 TestNDK.cpp 文件调用 NDKTest.c 文件中的 stringFromJni2() 函数。

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

#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");

【讨论】:

以上是关于在 Android JNI/NDK 代码中从 C++ 函数调用 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

Android JNI/NDK开发JNI实现C/C++与Android/JAVA相互调用

Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

JNI/NDK开发指南(开山篇)

AS2.2使用CMake方式进行JNI/NDK开发

Android JNI&NDK编程小结及建议

使用预编译的C共享库与JNI / NDK