安卓是java ios c_如何为Android和iOS使用相同的C ++代码?

更新。

这个答案在我写完四年后很受欢迎,在这四年里,很多事情都发生了变化,所以我决定更新我的答案以更好地适应我们当前的现实。 答案的想法没有改变; 实施已经改变了一点。 我的英语也发生了变化,它已经有了很大的改进,所以现在每个人的答案都更容易理解。

请查看repo,以便下载并运行我将在下面显示的代码。

答案

在我展示代码之前,请在下图中采取很多措施。

tM6qG.png

每个操作系统都有其UI和特性,因此我们打算在这方面为每个平台编写特定的代码。 另一方面,我们打算使用C ++编写所有逻辑代码,业务规则和可共享的东西,因此我们可以将相同的代码编译到每个平台。

在图中,您可以看到最低级别的C ++层。 所有共享代码都在此段中。 最高级别是常规的Obj-C / Java / Kotlin代码,这里没有新闻,困难的部分是中间层。

iOS中间层很简单; 您只需要将项目配置为使用Obj-c的变体(即Objective-C ++)进行构建,并且完全可以访问C ++代码。

在Android方面,事情变得更加困难,Android上的Java和Kotlin语言都在Java虚拟机下运行。 因此访问C ++代码的唯一方法是使用JNI,请花时间阅读JNI的基础知识。 幸运的是,今天的Android Studio IDE在JNI方面有很大的改进,在编辑代码时会显示很多问题。

代码逐步完成

我们的示例是一个简单的应用程序,您可以将文本发送到CPP,并将该文本转换为其他内容并将其返回。 这个想法是,iOS将发送“Obj-C”,Android将从他们各自的语言发送“Java”,CPP代码将创建一个文本作为跟随“cpp说你好<< text received>>”。

共享CPP代码

首先,我们将创建共享的CPP代码,为此我们有一个简单的头文件,其中包含接收所需文本的方法声明:

#include

const char *concatenateMyStringWithCppString(const char *myString);

CPP实施:

#include

#include "Core.h"

const char *CPP_BASE_STRING = "cpp says hello to %s";

const char *concatenateMyStringWithCppString(const char *myString) {

char *concatenatedString = new char[strlen(CPP_BASE_STRING) + strlen(myString)];

sprintf(concatenatedString, CPP_BASE_STRING, myString);

return concatenatedString;

}

Unix的

一个有趣的好处是,我们也可以使用相同的代码用于Linux和Mac以及其他Unix系统。 这种可能性特别有用,因为我们可以更快地测试我们的共享代码,因此我们将创建一个Main.cpp,如下所示,从我们的机器执行它,看看共享代码是否正常工作。

#include

#include

#include "../CPP/Core.h"

int main() {

std::string textFromCppCore = concatenateMyStringWithCppString("Unix");

std::cout << textFromCppCore << '\n';

return 0;

}

要构建代码,您需要执行:

$ g++ Main.cpp Core.cpp -o main

$ ./main

cpp says hello to Unix

iOS版

是时候在移动端实施了。 至于iOS有一个简单的集成,我们从它开始。 我们的iOS应用程序是一个典型的Obj-c应用程序,只有一个区别; 文件是jstring而不是const char *.即它是一个Obj-C ++应用程序,而不是Obj-C应用程序。

为了更好的组织,我们创建CoreWrapper.mm如下:

#import "CoreWrapper.h"

@implementation CoreWrapper

+ (NSString*) concatenateMyStringWithCppString:(NSString*)myString {

const char *utfString = [myString UTF8String];

const char *textFromCppCore = concatenateMyStringWithCppString(utfString);

NSString *objcString = [NSString stringWithUTF8String:textFromCppCore];

return objcString;

}

@end

该类有责任将CPP类型和调用转换为Obj-C类型和调用。 一旦你可以在Obj-C上的任何文件上调用CPP代码,这不是强制性的,但是它有助于保持组织,并且在你的包装文件之外你维护一个完整的Obj-C样式代码,只有包装文件成为CPP样式。

将包装器连接到CPP代码后,可以将其用作标准的Obj-C代码,例如视图控制器”

#import "ViewController.h"

#import "CoreWrapper.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

NSString* textFromCppCore = [CoreWrapper concatenateMyStringWithCppString:@"Obj-C++"];

[_label setText:textFromCppCore];

}

@end

看看应用程序的外观:

hWJdL.png

WUj51.png

Android的

现在是Android集成的时候了。 Android使用Gradle作为构建系统,而使用CMake的C / C ++代码。 所以我们需要做的第一件事就是在gradle文件上配置CMake:

android {

...

externalNativeBuild {

cmake {

path "CMakeLists.txt"

}

}

...

defaultConfig {

externalNativeBuild {

cmake {

cppFlags "-std=c++14"

}

}

...

}

第二步是添加CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.4.1)

include_directories (

../../CPP/

)

add_library(

native-lib

SHARED

src/main/cpp/native-lib.cpp

../../CPP/Core.h

../../CPP/Core.cpp

)

find_library(

log-lib

log

)

target_link_libraries(

native-lib

${log-lib}

)

在CMake文件中,您需要添加将在项目中使用的CPP文件和头文件夹,在我们的示例中,我们添加了jstring文件夹和Core.h / .cpp文件。 要了解有关C / C ++配置的更多信息,请阅读它。

现在核心代码是我们应用程序的一部分,是时候创建桥梁,为了使事情更简单和有条理,我们创建一个名为CoreWrapper的特定类作为JVM和CPP之间的包装:

public class CoreWrapper {

public native String concatenateMyStringWithCppString(String myString);

static {

System.loadLibrary("native-lib");

}

}

请注意,此类有一个jstring方法,并加载一个名为const char *的本机库。这个库是我们创建的库,最后,CPP代码将成为共享对象jstring文件嵌入我们的APK,JNIEnv*将加载它。 最后,当您调用本机方法时,JVM会将调用委托给已加载的库。

现在Android集成中最奇怪的部分是JNI; 我们需要一个cpp文件,在我们的例子中是“native-lib.cpp”:

extern "C" {

JNIEXPORT jstring JNICALL Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString(JNIEnv *env, jobject /* this */, jstring myString) {

const char *utfString = env->GetStringUTFChars(myString, 0);

const char *textFromCppCore = concatenateMyStringWithCppString(utfString);

jstring javaString = env->NewStringUTF(textFromCppCore);

return javaString;

}

}

您将注意到的第一件事是jstring这部分是JNI正确使用我们的CPP代码和方法链接所必需的。 您还将看到JNI用于与JVM一起使用的一些符号,如const char *和jstring.为了理解这些内容的含义,有必要花一些时间阅读它,因为本教程的目的只是将这些内容视为样板。

一个重要的事情,通常是许多问题的根源是方法的名称; 它需要遵循“Java_package_class_method”模式。 目前,Android studio对它有很好的支持,因此它可以自动生成这个样板,并在它正确或未命名时显示给你。 在我们的示例中,我们的方法名为“Java_ademar_androidioscppexample_CoreWrapper_concatenateMyStringWithCppString”,因为“ademar.androidioscppexample”是我们的包,所以我们替换“。” 通过“_”,CoreWrapper是我们链接本机方法的类,“concatenateMyStringWithCppString”是方法名称本身。

正如我们正确声明的方法是分析参数的时候,第一个参数是jstring的指针,这是我们访问JNI的方式,对于我们很快就会进行转换至关重要。 第二个是const char *它是您用来调用此方法的对象的实例。 您可以将其视为java“this”,在我们的示例中我们不需要使用它,但我们仍然需要声明它。 在这个jobject之后,我们将接收该方法的参数。 因为我们的方法只有一个参数 - 一个字符串“myString”,所以我们只有一个名字相同的“jstring”。 还要注意我们的返回类型也是一个jstring。 这是因为我们的Java方法返回一个String,有关Java / JNI类型的更多信息,请阅读它。

最后一步是将JNI类型转换为我们在CPP端使用的类型。 在我们的例子中,我们正在将jstring转换为const char *,将其转换为CPP,得到结果并转换回jstring。正如JNI上的所有其他步骤一样,并不难; 它只是用于电镀,所有的工作都是通过我们拨打GetStringUTFChars和NewStringUTF时收到的JNIEnv*参数完成的。之后我们的代码已准备好在Android设备上运行,让我们一起来看看。

U9A8h.png

MOAJZ.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值