2013-03-02 23 views
2

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

这个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(字符* 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; 

    } 

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

+0

我怀疑你可以使用'std :: string'返回值与JNI进行交互 – 2013-03-02 12:02:27

回答

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,构建脚本来生成代码的共享库。请务必将NDK1.cpp文件放在jni文件夹中的Android.mk文件所在的目录中(假设您不想更改Android.mk文件以在其他地方查找源文件)。 假设你使用的是Linux(我不知道它如何适用于Windows),你应该打开一个终端,你有你的Android.mk。你必须运行命令'ndk-build'。如果一切正常,您将不会收到任何错误,并且.so文件将被复制到项目的libs文件中。

更新: 也许你需要添加stl库来使用字符串类。您可以尝试在同一目录下添加一个Application.mk文件作为Android.mk与此内容:

APP_ABI := armeabi armeabi-v7a 
APP_STL := gnustl_static 
+0

好的,我已经写了MainActivity 但是C++代码和.mk文件怎么样,这一切都正确吗? – Hana90 2013-03-02 12:34:01

+0

@Dondon我编辑了我的文章,尝试运行ndk-build,看看会发生什么。如果您遇到一些错误,您可以在这里发布以查看问题。 我不确定你使用的这个popen是否有效,反正... – Esparver 2013-03-02 12:38:51

+0

你能编辑你的答案吗?包括NDK1.cpp代码和Android.mk? – Hana90 2013-03-02 12:48:17

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); 
} 

,你也必须在Android.mk在Eclipse中添加链接“日志”和“Android”的库或在Build中。gradle这个(Android Studio中)的Android {}标签

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

里面,如果你Android Studio中

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}) 

使用外部CMakeList.txt和u还必须声明JNI C++这样

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

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