代码之家  ›  专栏  ›  技术社区  ›  chrizonline

如何在Android中使用c++

  •  1
  • chrizonline  · 技术社区  · 7 年前

    我有两个问题。

    1. 如何将c++源文件编译成android?
    2. 如何使用已经生成的c++.so文件

    我的开发环境:

    • 窗口10
    • 安卓工作室3.1.4

    第一季度

    我有MyClass.h和MyClass.cpp要在Android中使用。我看到的所有示例都是调用helloJni.cpp中的cpp函数。如何调用helloJni.cpp中的其他.cpp/.h文件??

    这些是我创造的。

    app/src/main/cpp/MyClass.h版

    #ifndef MYCLASS_H_
    #define MYCLASS_H_
    
    class MyClass {
        public:
            MyClass();
            virtual ~MyClass();
            std::string hello();
    };
    
    #endif /* MYCLASS_H_ */
    

    应用程序/src/main/cpp/MyClass.cpp

    #include <iostream>
    #include "MyClass.h"
    #include <string>
    using namespace std;
    
    MyClass::MyClass() {
        // TODO Auto-generated constructor stub
    
    }
    
    MyClass::~MyClass() {
        // TODO Auto-generated destructor stub
    }
    
    string MyClass::hello() {
        string s = "hello from MyClass";
        return s.c_str();
    }
    

    #include <jni.h>
    #include <string>
    #include "MyClass.h"
    
    extern "C"
    
    JNIEXPORT jstring JNICALL Java_com_example_MainActivity_stringFromHello(
            JNIEnv *env,
            jobject /* this */) {
        MyClass myClass;
        return env->NewStringUTF(myClass.hello().c_str());
    }
    

    app/src/main/java/com/example/MainActivity.java

    public class MainActivity extends AppCompatActivity {
        static {
            System.loadLibrary("helloJni");
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TextView jni2 = findViewById(R.id.jni_2);
            jni2.setText(stringFromHello());
        }
    
        public native String stringFromHello();
    
    }
    

    应用程序/CMakeLists.txt

    # Sets the minimum version of CMake required to build your native library.
    # This ensures that a certain set of CMake features is available to
    # your build.
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # Specifies a library name, specifies whether the library is STATIC or
    # SHARED, and provides relative paths to the source code. You can
    # define multiple libraries by adding multiple add_library() commands,
    # and CMake builds them for you. When you build your app, Gradle
    # automatically packages shared libraries with your APK.
    
    add_library( # Specifies the name of the library.
                  helloJni
    
                  # Sets the library as a shared library.
                  SHARED
    
                  # Provides a relative path to your source file(s).
                  src/main/cpp/helloJni.cpp )
    
     add_library( # Specifies the name of the library.
                   MyClass
    
                   # Sets the library as a shared library.
                   SHARED
    
                   # Provides a relative path to your source file(s).
                   src/main/cpp/MyClass.cpp )
    
    # Specifies a path to native header files.
    include_directories(src/main/cpp/)
    

    在Android Studio中生成时出错:

    Build command failed.
    Error while executing process C:\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:SomeDir\android\TestNdk\app\.externalNativeBuild\cmake\debug\x86_64 --target helloJni}
    [1/2] Building CXX object CMakeFiles/helloJni.dir/src/main/cpp/helloJni.cpp.o
    [2/2] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libhelloJni.so
    FAILED: cmd.exe /C "cd . && C:\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe  --target=x86_64-none-linux-android --gcc-toolchain=C:/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=C:/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Android/Sdk/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11  -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LC:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libhelloJni.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libhelloJni.so CMakeFiles/helloJni.dir/src/main/cpp/helloJni.cpp.o  -latomic -lm "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a" "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++abi.a" && cd ."
    C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:18: error: undefined reference to 'MyClass::MyClass()'
    C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:19: error: undefined reference to 'MyClass::hello()'
    C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:22: error: undefined reference to 'MyClass::~MyClass()'
    C:SomeDir\android\TestNdk\app\src\main\cpp/helloJni.cpp:22: error: undefined reference to 'MyClass::~MyClass()'
    clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
    ninja: build stopped: subcommand failed.
    

    问题2

    • 我需要创建JNI cpp文件吗?我跟着 here ,但它没有提到任何JNI文件?是因为.so文件是用JNI编译的吗?
    • 有没有一篇好文章给我指明了正确的方向?

    ================================

    更新

    libCSharedLib.dll 包含以下文件的eclipse中的库:

    福巴.h

    #ifndef FOOBAR_H_
    #define FOOBAR_H_
    
    class Foobar {
        public:
            Foobar();
            virtual ~Foobar();
            int wave();
    };
    
    
    
    #endif /* FOOBAR_H_ */
    

    #include "Foobar.h"
    
    #include <iostream>
    
    Foobar::Foobar() {
        // TODO Auto-generated constructor stub
    
    }
    
    Foobar::~Foobar() {
        // TODO Auto-generated destructor stub
    }
    
    int Foobar::wave() {
        return 1;
    }
    

    已更新CMakeList.txt:

    # Sets the minimum version of CMake required to build your native library.
    # This ensures that a certain set of CMake features is available to
    # your build.
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # Specifies a library name, specifies whether the library is STATIC or
    # SHARED, and provides relative paths to the source code. You can
    # define multiple libraries by adding multiple add_library() commands,
    # and CMake builds them for you. When you build your app, Gradle
    # automatically packages shared libraries with your APK.
    
    add_library( # Specifies the name of the library.
                  helloJni
    
                  # Sets the library as a shared library.
                  SHARED
    
                  # Provides a relative path to your source file(s).
                  src/main/cpp/helloJni.cpp )
    
     add_library( # Specifies the name of the library.
                   MyClass
    
                   # Sets the library as a shared library.
                   SHARED
    
                   # Provides a relative path to your source file(s).
                   src/main/cpp/MyClass.cpp )
    
     add_library( # Specifies the name of the library.
                   foobarJni
    
                   # Sets the library as a shared library.
                   SHARED
    
                   # Provides a relative path to your source file(s).
                   src/main/cpp/foobarJni.cpp )
    
    add_library(libCSharedLib SHARED IMPORTED)
    set_target_properties(libCSharedLib PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libCSharedLib.dll)
    
    # Specifies a path to native header files.
    include_directories(src/main/cpp/)
    
    target_link_libraries(helloJni MyClass foobarJni libCSharedLib)
    

    我把Foobar.h放入 src/main/cpp

    foobarJni.cpp(忽略我没有返回int值。只是在这里测试)

    #include <jni.h>
    #include <string>
    #include "Foobar.h"
    
    extern "C"
    
    JNIEXPORT jstring JNICALL Java_com_example_MainActivity_stringFoobar(
            JNIEnv *env,
            jobject /* this */) {
        Foobar foobar;
        int wave = foobar.wave();
    
        std::string s = "abc";
        return env->NewStringUTF(s.c_str());
    }
    

    主要活动:

    public class MainActivity extends AppCompatActivity {
        static {
            System.loadLibrary("helloJni");
            System.loadLibrary("foobarJni");
        }
    ....
    }
    

    但我仍然得到错误“未定义对Foobar的引用…”

        Build command failed.
    Error while executing process C:\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\somedir\TestNdk\app\.externalNativeBuild\cmake\debug\x86_64 --target helloJni}
    [1/6] Building CXX object CMakeFiles/foobarJni.dir/src/main/cpp/foobarJni.cpp.o
    [2/6] Building CXX object CMakeFiles/MyClass.dir/src/main/cpp/MyClass.cpp.o
    [3/6] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libfoobarJni.so
    FAILED: cmd.exe /C "cd . && C:\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe  --target=x86_64-none-linux-android --gcc-toolchain=C:/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=C:/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Android/Sdk/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11  -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LC:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libfoobarJni.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libfoobarJni.so CMakeFiles/foobarJni.dir/src/main/cpp/foobarJni.cpp.o  -latomic -lm "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a" "C:/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++abi.a" && cd ."
    C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:19: error: undefined reference to 'Foobar::Foobar()'
    C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:20: error: undefined reference to 'Foobar::wave()'
    C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:24: error: undefined reference to 'Foobar::~Foobar()'
    C:\somedir\TestNdk\app\src\main\cpp/foobarJni.cpp:24: error: undefined reference to 'Foobar::~Foobar()'
    clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
    ninja: build stopped: subcommand failed.
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   JBL    7 年前

    您得到一个未定义的引用,因为在编译时 helloJni.cpp ,尽管它可以通过头找到声明,但是在链接时缺少定义。您可以通过将HelloJni库与MyClass库链接来解决这个问题,或者将这两个文件作为同一个库的一部分(我建议您这样做)。

    至于您的后续问题,如果您已经有了一个.so文件,那么您可以使用它,如果它包含JNI代码,从而可以从Java类调用本机代码。否则,如果您无法控制该库,则可以添加另一个库,该库将在现有库周围包含一个JNI“包装器”。您需要记住链接到此现有库,否则将得到与此处相同的错误。

    System.loadLibrary("helloJni");
    

    您必须对要使用的每个库执行此操作,并确保在运行时可以找到这些库(这主要意味着它们必须位于 jniLibs 文件夹)。

    关于如何在Android中使用本机代码的资源,我建议阅读 Android NDK Guide .