如何将c++代码转换为NDK

how to convert C++ code for NDK?

本文关键字:转换 NDK 代码 c++      更新时间:2023-10-16

这个代码通过使用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。可

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

如何整理这些文件才能有一个正确的解决方案

您仍然需要带有本机方法声明的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库来使用字符串类。您可以尝试添加应用程序。. mk文件与Android. mk文件放在同一目录下。Mk:

APP_ABI := armeabi armeabi-v7a
APP_STL := gnustl_static

Android不允许直接从内部或外部存储读取文件。这就是为什么所有人都使用Android操作系统,因为它可以屏蔽安全漏洞。İf如果你想用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中添加链接器"log"answers"android"库。在Eclipse或Build中。gradle(Android Studio) inside Android {} tag

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

和u也必须像这样声明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天写这个代码。享受和支持开源;)