3

此代码使用 C++ 代码调用 Linux 命令,但如何将其转换为通过 NDK 将其用作 lib?我看到仅使用 .C 文件的示例,以及 Jni 使用的变量与 C++ 变量不同。

这个 c++ 代码我需要将其转换为使用它,然后与 NDK 一起使用

#include <string>
#include <iostream>
#include <stdio.h>

std::string exec(char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
    if(fgets(buffer, 128, pipe) != NULL)
        result += buffer;
}
pclose(pipe);
return result;
}

这适合做吗?

Android.mk中

LOCAL_PATH := $(call my-dir)

 include $(CLEAR_VARS)

 # Here we give our module name and source file(s)
 LOCAL_MODULE    := NDK1
 LOCAL_SRC_FILES := NDK1.cpp
include $(BUILD_SHARED_LIBRARY)

假设我的本机方法是 exec(char* cmd),对于NDK1.cpp

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

  jstring Java_com_mindtherobot_samples_ndkfoo_MainActivity_exec(JNIEnv*     env, jobject javaThis , Jchar* cmd) {

......... same code above
 return result;

  }

如何安排这些文件以获得正确的解决方案?

4

2 回答 2

4

您仍然需要带有本机方法声明的 MainActivity java 代码。我不知道您是没有发布它还是忘记实施它。它应该是这样的:

public class MainActivity extends Activity
{

    /*Don't forget to load the library!!*/
    static {
        System.loadLibrary("NDK1");
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // your initialization here...
    }

    public native String exec(String cmd);
}

此外,正如 g-makulik 在评论中指出的那样,您在本机代码中返回了一个 c++ 字符串,但您应该返回一个 Java 字符串。NDK1.cpp 文件应该类似于以下内容:

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

std::string exec(char* cmd) {
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
        result += buffer;
    }
    pclose(pipe);
    return result;
}

jstring Java_com_mindtherobot_samples_ndkfoo_MainActivity_exec(JNIEnv* env, jobject javaThis , Jchar* cmd) {
    std::string result = exec(cmd); 
    return (*env)->NewStringUTF(env, result);
}

最后,您应该运行 ndk-build 脚本来为您的代码生成共享库。请务必将 NDK1.cpp 文件与 Android.mk 文件放在 jni 文件夹中的同一目录中(假设您不想更改 Android.mk 文件以在其他地方查找源)。假设您使用的是 linux(我不知道它在 Windows 上是如何工作的),您应该打开一个终端,其中有您的 Android.mk。在那里你必须运行命令'ndk-build'。如果一切正常,您将不会收到任何错误,并且 .so 文件将被复制到项目的 libs 文件中。

更新:也许您需要添加 stl 库才能使用字符串类。您可以尝试在与 Android.mk 相同的目录中添加一个 Application.mk 文件,其中包含以下内容:

APP_ABI := armeabi armeabi-v7a
APP_STL := gnustl_static
于 2013-03-02T12:25:27.280 回答
0

Android 不允许直接从内部或外部存储读取文件。这就是为什么所有人都使用 Android 操作系统的原因,因为它可以阻止安全漏洞。如果您想使用 C++ 本地代码读取文件,则必须使用来自 C++ 的 Java Api 调用。

AAssetManager* mgr = AAssetManager_fromJava(env,assetManager);
AAsset* asset = AAssetManager_open(mgr,"textfile.txt", AASSET_MODE_UNKNOWN);

if (NULL == asset) {

    return; //exit with error not loaded
}
long size = AAsset_getLength(asset);
char* buffer = (char*) malloc (sizeof(char)*size);
AAsset_read (asset,buffer,size);
AAsset_close(asset);
free(buffer);

这就对了。您还必须从 java 传递assetManager

public native void readTxtFile(AssetManager assetManager);

并使用此功能获取资源

AssetManager  assetMgr; //define this as global variable

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
assetMgr = getResources().getAssets(); //very important dont forget!
readTxtFile(assetMgr);
}

并且您还必须在 Eclipse 的 Android.mk 或 android{} 标签内的 Build.gradle(Android Studio) 中添加链接器“log”和“android”库

ndk {
        moduleName "your_module_name"
        ldLibs "android","log"
        //ldLibs.add("android")
    }

如果您在 Android Studio 中使用外部 CMakeList.txt

find_library( # Sets the name of the path variable.
          android-lib

          # Specifies the name of the NDK library that
          # you want CMake to locate.
          android )
find_library( # Sets the name of the path variable.
          log-lib

          # Specifies the name of the NDK library that
          # you want CMake to locate.
          log )

target_link_libraries( native-lib 
                   ${log-lib}
                    ${android-lib})

而且你还必须像这样声明 Jni c++ 函数

void Java_com_example_lenovo_firstopencv_MainActivity_salt(JNIEnv *env,
jobject instance,jobject assetManager) { /*copy above c++ code to here*/}

不要忘记在主文件夹中创建资产文件夹,因为您的文件(textfile.txt)位于资产文件夹中,并且资产管理器对象从那里读取。这就对了。我花了 2 天时间来编写这段代码。享受并支持开源;)

于 2017-04-04T22:03:51.067 回答