【问题标题】:Porting a CPP application to Android将 CPP 应用程序移植到 Android
【发布时间】:2014-08-22 11:25:03
【问题描述】:

我需要将CPP 项目移植到Android,但由于以下我不确定的事情,我不知何故被卡住了:

  1. 我是否需要为我的CPP 项目使用某种Java 包装器,即我是否必须使用Android SDK 将我的应用程序与Android 集成?如果有另一种方式,那会是哪一种?

  2. 我看到一些人声称他们已经能够操纵他们的 cmake 文件和一些自定义的 android-cmake toolchain 来构建他们的 “.so” 或最终从他们的项目中构建一个 “.apk”。如果没有 java 包装器来操作 cpp 项目的 cmake 文件来构建您的项目,是否有可能? (来源:Build Android NDK project with Cmake

【问题讨论】:

    标签: java android c++ android-ndk cmake


    【解决方案1】:

    根据我的经验,我会使用 android java 入口点,否则你很可能会遇到问题(你可以制作完整的原生 android 应用程序,但我强烈建议不要这样做)。

    其中一个原因是您希望从 CPP 内部调用 SDK 函数,并且从 CPP 对 java 环境使用反射并非易事。

    步骤如下:

    1. 创建一个非常简单的 C 代码,作为 CPP 代码的桥梁。以下是我常用的一些示例 C 函数:
      • OnApplicationStart
      • OnApplicationPaused
      • OnApplicationResumed
      • OnApplicationUpdate
      • OnTouchReceived
    2. 导出这些函数并将它们加载到您的 Java 代码中(查找 JNI 以了解如何执行此操作)
    3. 在 Java 中处理所有 Android 特定操作,以及在 cpp 中处理所有应用程序特定操作

    所以第一个问题的答案是 java 包装器不是强制性的,但强烈推荐。

    回答你的第二个问题:

    是的,您可以使用 cmkae、ant、cygwin 等各种命令工具来创建您的 apk(取决于您自己的感觉如何)。您仍然会使用 android 编译器,因为您的目标是 arm。

    不同之处在于您需要在 manifest.xml 中将应用程序的入口点从普通活动更改为原生活动 (http://developer.android.com/reference/android/app/NativeActivity.html)。

    如您所见,区别不在于构建系统,而在于您定义入口点的方式。

    作为一个友好的建议,请尝试使用最小的 java 包装方法。您可能会更快地获得更好的结果,并且不会花费您超过 1 周的时间在网上研究如何将 java 代码链接到 cpp。

    编辑:

    根据需要,我将简要说明我将如何处理将 CPP 应用程序移植到 Android 的过程:

    1. 重新考虑将您的应用程序用作共享库,使用 C 入口点:

    a.创建一个简单的 C 应用程序,该应用程序将加载 yourCPPApp.dll(如果您使用的是 linux,则为 .so)

    b.在您的 .dll 中创建要导出的最少必要的 extern "C" 函数,以便为您的 dll 提供必要的信息

    为简单起见,我们假设我们有 3 个方法:

     void StartApplication();
     bool OnApplicationUpdate();
     void OnScreenTouched(int x, int y);
    

    c。实现简单的 C 项目,该项目将在外部调用这些方法(因此 .exe 将从 .dll 调用方法!)

    示例代码:

     #include "myCPPapp.h"
     int main(int arg, char** argv)
     {
          StartApplication();
          srand(time(NULL));
          while (OnApplicationUpdate())
          {
              // we assume we have a 480x640 resolution
              OnScreenTouched(rand()%480,rand()%640);
          }
          return 0;
     }
    
    1. 现在我们已经有了使用 .exe 和 .dll 完全本地运行的东西,是时候让它使用 .apk 和 .so 了

    一个。将暴露的方法从 myCppApp 重命名为 java 兼容的原型

    extern "C" {
        JNIEXPORT void JNICALL Java_com_sample_nativebridge_OnApplicationStart(JNIEnv env, jobject thiz);
        JNIEXPORT jboolean JNICALL Java_com_sample_nativebridge_OnApplcationUpdate(JNIEnv env, jobject thiz);
        JNIEXPORT void JNICALL Java_com_sample_nativebridge_OnScreenTouched(JNIEnv env, jobject thiz, jint x, jint y);
    }
    

    b.在 com.sample 包中创建 java 类 nativebridge(区分大小写)(您需要尊重名称才能正确链接到本机)

    class nativebridge {
        public static native void OnApplicationStart();
        public static native boolean OnApplicationUpdate();
        public static native void OnScreenTouched(int x, int y);
    }
    

    c。在本机桥中添加加载库语句,以便在运行时加载您的库

    class nativebridge {
      ....
      static {
        System.loadLibrary("myCppApp"); 
        // notice that the lib prefix and .so sufix aren't part of the name
      }
    }
    

    d。使用 armeabi 编译器编译您的 CPP 代码并创建 libmyCPPApp.so(ndk 构建系统,或任何您想要的...我会使用 ndk,这很容易,只需进入带有 Android.mk 的文件夹并调用 $ ANDROID_NDK_BUILD_PATH/build)

    此时您需要创建一个 .mk 文件来编译您的 myCppApp 代码,但这超出了范围,您需要自己进行这项研究(一旦掌握了它,这将非常简单)。

    c。在您认为合适的任何地方使用 Java 应用程序内部桥接器中的本机方法。

    一个很好的提示是通过 ndk 的 hello world 示例:

    http://www.ntu.edu.sg/home/ehchua/programming/android/android_ndk.html

    享受吧。

    【讨论】:

    • 我非常感谢您为写出这么好的答案所付出的努力。然而,我仍然遇到一些问题,主要是因为我是 Android 的新手。因此,据我了解,创建.apk 是您最终想要实现的目标,即使用.apk,您可以将项目部署到Android 设备。如果这是正确的,那么根据您对我的第二个问题的回复,我唯一要做的就是使用cmakeandroid-cmake-apk 构建我的代码并将其部署到Android。你觉得这可行吗?
    • 关于移植的另一个问题是,正如您所提到的,我最终必须使用java wrapper。我看到人们使用它的方式是: 1. 在java 文件中声明将本机实现的方法; 2.编译这些java文件,得到native functions signatures在一个.h文件中; 3. 使用已经生成的签名实现.CPP文件中的native functions。但是,我认为我无法做到这一点,因为我正在处理一个已经用.CPP 编写的项目。有没有其他方法可以整合这个java wrapper
    • 你不需要编译java来获取本地签名。你需要遵循一个简单的命名约定。例如,要拥有一个 java 本地函数 int com.samplepackage.nativebridge.dosomething(string smthing) ,您需要使用以下语法声明一个 Extern "C" 函数 "JNICALL jint JNIEXPORT Java_com_samplepackage_nativebridge_dosomething(JNIEnv env, jclass this, jstring smthing)。然后,在您调用 System.loadLibrary(yourLib) 之后,这两个函数将匹配,您将能够使用它们。
    • 所以你可以反过来(我个人觉得这更令人欣慰):创建你的 c++ 代码工作所需的 extern "C" 函数,然后创建必要的 java 类。
    • 关于代码构建,你构建的任何东西都可以,只要你用正确的编译器为正确的处理器架构编译本机(最常见的是 armeabi-v7a,它带有 ndk) .
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 2010-12-07
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多