java - 如何设置 Android Studio 以使用原生库?

标签 java android c++ android-ndk

要点:

我想从 Java 调用 C/C++ 函数。

我的工作:

  • 我可以使用“javah”程序生成 .h 文件。它正确地吐出了我的头文件。完美的。我添加了两个包含此头文件的 .c 文件,其中只有一个实现了该功能。由于 Android NDK 构建系统中的错误,第二个是一个完全空的 .c 文件。到目前为止一切都很好。

  • 我使用 Android NDK“ndk-build”脚本为多个不同的平台生成我的 .so 文件。同样,完美运行。

  • 我将这些库文件(在它们各自的文件夹中)添加到我的 Android Studio 项目中的 jniLibs 文件夹中。 Gradle 会看到它们,并在构建时正确地将它们添加到我的 .apk 文件中。

  • 在我的应用程序源代码中,我使用 static { System.loadLibrary("testLib"); }。 (是的,这是正确的文件名)。它加载成功没有问题。

问题:

一旦我尝试调用 native 函数(在 java 中定义并在 C++ 中实现),我就会收到以下异常:

java.lang.UnsatisfiedLinkError: Native method not found:    
com.example.nativeapp.MainActivity.testNativeMethod:()Ljava/lang/String;"

这就是事情变得奇怪的地方:/:我在我的应用程序代码中使用 NDK 成功编译,使用 Gradle 成功构建,并使用 Java 成功“loadLibrary”。但是,当简单地调用函数“testNativeMethod();”时,就会出现运行时异常和应用程序崩溃。

这是我的“javah”生成的头文件:

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

#ifndef _Included_com_example_nativeapp_MainActivity
#define _Included_com_example_nativeapp_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_example_nativeapp_MainActivity_MODE_PRIVATE
#define com_example_nativeapp_MainActivity_MODE_PRIVATE 0L
#undef com_example_nativeapp_MainActivity_MODE_WORLD_READABLE
#define com_example_nativeapp_MainActivity_MODE_WORLD_READABLE 1L
#undef com_example_nativeapp_MainActivity_MODE_WORLD_WRITEABLE
#define com_example_nativeapp_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef com_example_nativeapp_MainActivity_MODE_APPEND
#define com_example_nativeapp_MainActivity_MODE_APPEND 32768L
#undef com_example_nativeapp_MainActivity_MODE_MULTI_PROCESS
#define com_example_nativeapp_MainActivity_MODE_MULTI_PROCESS 4L
#undef com_example_nativeapp_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define com_example_nativeapp_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef com_example_nativeapp_MainActivity_BIND_AUTO_CREATE
#define com_example_nativeapp_MainActivity_BIND_AUTO_CREATE 1L
#undef com_example_nativeapp_MainActivity_BIND_DEBUG_UNBIND
#define com_example_nativeapp_MainActivity_BIND_DEBUG_UNBIND 2L
#undef com_example_nativeapp_MainActivity_BIND_NOT_FOREGROUND
#define com_example_nativeapp_MainActivity_BIND_NOT_FOREGROUND 4L
#undef com_example_nativeapp_MainActivity_BIND_ABOVE_CLIENT
#define com_example_nativeapp_MainActivity_BIND_ABOVE_CLIENT 8L
#undef com_example_nativeapp_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#define com_example_nativeapp_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef com_example_nativeapp_MainActivity_BIND_WAIVE_PRIORITY
#define com_example_nativeapp_MainActivity_BIND_WAIVE_PRIORITY 32L
#undef com_example_nativeapp_MainActivity_BIND_IMPORTANT
#define com_example_nativeapp_MainActivity_BIND_IMPORTANT 64L
#undef com_example_nativeapp_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define com_example_nativeapp_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef com_example_nativeapp_MainActivity_CONTEXT_INCLUDE_CODE
#define com_example_nativeapp_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undef com_example_nativeapp_MainActivity_CONTEXT_IGNORE_SECURITY
#define com_example_nativeapp_MainActivity_CONTEXT_IGNORE_SECURITY 2L
#undef com_example_nativeapp_MainActivity_CONTEXT_RESTRICTED
#define com_example_nativeapp_MainActivity_CONTEXT_RESTRICTED 4L
#undef com_example_nativeapp_MainActivity_RESULT_CANCELED
#define com_example_nativeapp_MainActivity_RESULT_CANCELED 0L
#undef com_example_nativeapp_MainActivity_RESULT_OK
#define com_example_nativeapp_MainActivity_RESULT_OK -1L
#undef com_example_nativeapp_MainActivity_RESULT_FIRST_USER
#define com_example_nativeapp_MainActivity_RESULT_FIRST_USER 1L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_DISABLE
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_DIALER
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_DIALER 1L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SHORTCUT
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
 * Class:     com_example_nativeapp_MainActivity
 * Method:    testNativeMethod
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_nativeapp_MainActivity_testNativeMethod
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

这是我的 .c 实现文件:

#include "com_example_nativeapp_MainActivity.h"

JNIEXPORT jstring JNICALL Java_com_example_nativeapp_MainActivity_testNativeMethod(JNIEnv* environment, jobject obj)
{
    return ( *env )->NewStringUTF(env, "HELLO FROM C Native!");
}

最后但同样重要的是,这是我的 .java 应用程序文件:

package com.example.nativeapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;


public class MainActivity extends Activity
{

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

    private TextView mDebugText;

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

        mDebugText = (TextView)findViewById(R.id.debug_text);

        // Here is where my native function call takes place. Without this, the app does (NOT) crash.
        mDebugText.setText(testNativeMethod());
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public native String testNativeMethod();
}

提前致谢。这绝对是那些冲击显示器类型的问题之一。

快速提醒一下:

我试过这个:https://www.youtube.com/watch?v=okLKfxfbz40 连续三次完美的按照步骤操作,还是失败。

此外,我一直在阅读 Stackoverflow 上的相关资料,但没有一个问题与我的情况相符。他们都在使用 opencv 等,我只想制作自己的“Hello World”Android NDK 库。再次提前致谢。

经过编辑以修复格式问题以提高可读性。

最佳答案

已修复。

修复:

我将 main.c 更改为 main.cpp 文件,这样我就可以使用“extern “C””。这样我就知道我正在正确调用 C 编译器。

这是我的新 main.c 文件(现在称为 main.cpp)(与上面的 OP 源比较^^^^^):

extern "C"
{
    #include "com_example_nativeapp_MainActivity.h"

    JNIEXPORT jstring JNICALL Java_com_example_nativeapp_MainActivity_testNativeMethod(JNIEnv* env, jobject obj)
    {
        return env->NewStringUTF("HELLO FROM C Native!");
    }
}

关于java - 如何设置 Android Studio 以使用原生库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24050223/

相关文章:

c++ - 在cpp函数中初始化多个结构

Java 应用程序作为系统服务

java - 它是一个正确的 JSON 文件吗?

java - 删除 ListView 项之间的间距

android - 在我的手机上更改 Android API 级别

java - 错误 : "Cannot make a static reference to the non-static method startActivity(Intent) from the type Activity"

java - 禁用加速度计并使用按键输入对其进行模拟

java - 从 JSF 应用程序的任何 Web 浏览器强制另存为对话

c++ - gdb 核心无法访问内存

c++ - 这个变量参数符号是如何工作的?