2013-03-02 27 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;)