如何转换NDK的C ++代码?

时间:2013-03-02 11:41:02

标签: android c++ android-ndk java-native-interface native

此代码使用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;

  }

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

2 个答案:

答案 0 :(得分:3)

您仍然需要使用本机方法声明的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

答案 1 :(得分: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”libs

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*/}

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