如何在Android和iOS之间实现代码共享

45

我将逐渐转向开发iPhone应用程序,远离严格的Android开发。我的理解是,我可以使用C/C++编写iOS应用程序的后端,并且我也可以使用NDK将C/C++代码包含在Android应用程序中。但我的问题是如何做到这一点?我已经搜索了很多,但没有找到清晰明确的答案。

当查看使用NDK的示例代码时,似乎所有的函数名称等都是特定于Android(或至少是Java)的,因此我将无法使用这个C/C++后端来开发iPhone前端? 希望能就此问题得到澄清,如果可能的话,提供一些代码来帮助我(即使只是一个简单的Hello World,从C/C++文件中读取一个字符串并在iOS和Android应用程序中显示它)。

谢谢大家。 Chris


1
NDK 不是用于创建跨平台应用程序的。它是用于使用本地语言编写时间敏感代码的。 - Falmarri
1
我明白了,感谢你的回答。你能给我建议如何编写跨平台的代码(例如共享算法等)吗? - Sonoman
@Falmarri:从 http://developer.android.com/sdk/ndk/index.html 的 NDK 文档中可以看到,“这可以为某些类别的应用程序提供好处,以重用现有代码”的形式。 - Roddy
3
无论谷歌对NDK的目的表述如何,如果它“不是”用于创建跨平台应用程序,那么您建议开发人员如何完成呢?将代码从Java移植到Objective C是浪费时间的,因为您可以在C++中编写一次,同时为两个平台提供支持。当然,您不能使用NDK进行任何前端UI方面的工作(除非使用OpenGL),但是将所有后端逻辑都编写为C ++,然后构建单独的UI仍将节省时间。 - Mitch Lindgren
请参考 https://dev59.com/eG865IYBdhLWcg3wFqdV - David d C e Freitas
6个回答

69
请注意,我几乎只处理“商业/实用/生产力”应用程序;这些应用程序严重依赖于相当标准的UI元素,并期望与其平台良好集成。本答案反映了这一点。查看Mitch Lindgren对Shaggy Frog答案的评论,适用于游戏开发人员,他们面临完全不同的情况。
我认为@Shaggy Frog在这里是错误的。如果您在C++中拥有有效的、经过测试的代码,则没有理由不在Android和iPhone之间共享它,我曾经参与过这样的项目,它可以非常成功。但是需要避免一些危险。
最关键的是要小心“最低公共分母”。自包含的算法代码很容易共享。管理线程、网络通信或以其他方式与操作系统交互的复杂框架更具挑战性,因为这样做可能迫使您打破平台的范例并寻求适用于所有平台的LCD。特别是,我建议使用平台的框架编写网络代码。这通常需要采用“三明治”方法,其中顶层是特定于平台的,底层也是特定于平台的,而中间层是可移植的。如果设计得当,这是一件非常好的事情。
线程管理和定时器也应使用平台的框架。特别是,Java大量使用线程,而iOS通常依靠其运行循环来避免线程。当iOS使用线程时,强烈建议使用GCD。同样,解决方案是将真正可移植的算法隔离出来,让特定于平台的代码管理如何调用它们。
如果您有一个复杂的现有框架,其中线程非常多,并且具有许多网络或UI代码,则共享它可能会很困难,但我的建议仍然是寻找重构而不是重写的方法。
作为一名在Linux、Windows和Android上分享交叉平台代码的iOS和Mac开发人员,我可以说,Android是迄今为止最令人恼火的平台(Windows曾经拥有这个称号,但被Android超越了)。 Android存在许多不明智共享代码的情况,但仍有许多代码重用的机会应该被利用。

嗨,Rob,在你的回答中,你建议使用本地编写网络代码,我想知道用什么库来编写网络代码。cURL?或者如果我想使用普通套接字,是否可以在Android和iOS之间共享与套接字相关的代码? - neevek
2
我推荐使用本地网络。这样可以获得更好的电源管理、与证书钥匙链的集成、代理、认证系统和更简单的代码。相比于cURL,NSURLConnection要容易得多(因为我做了很多cURL工作)。Android也有很好的本地网络支持。在iOS上,最好使用GCDAsyncSocket https://github.com/robbiehanson/CocoaAsyncSocket/wiki/Intro_GCDAsyncSocket来处理低级套接字。这正是你不应该分享的代码。当你尝试分享时,你会发现自己需要手动管理NTLM身份验证,而不能免费获得它(真实故事)。 - Rob Napier
@RobNapier 我们有一个应用程序,在Android和iPhone中使用http web服务调用。但现在我们想编写一个通用的c/c++代码来调用这个http web服务,然后在Android和iPhone中使用该代码。您能告诉我从哪里开始吗? - Herry
2
如果你说的是Web服务,那么在iOS上使用SOAP真的很麻烦,我建议使用REST。它易于被两者消费,但我不建议共享代码。RESTKit、MKNetworkKit或其他iOS的REST工具包都非常好用。让所有的网络请求都在本地完成,然后只需在共享的C++中消费数据,如果这种代码共享对你来说真的有很大的好处(但将C++集成到Android中很麻烦,所以最好是一个重大的好处)。 - Rob Napier
如果你必须使用SOAP,那么我建议你用gsoap编写你的处理程序。这样可以被两者共享。 - Rob Napier
Android是目前最令人头疼的平台之一,分享开发成果非常困难。五年过去了,情况依旧没有改变。使用NDK仍然是一件痛苦的事情。 - Dmitry Zaytsev

4
虽然这种方法很好(你遵循了不重复自己的原则),但只有在你能以高效的方式共享代码时,它才是实用的。在这种情况下,跨平台开发无法采用“一次编写”的方法,因为两个平台的代码需要用不同的语言编写(iPhone上使用C/C++/Obj-C,Android上使用Java)。
在这种情况下,最好编写两个不同语言的代码库。建议:不要像C++那样编写Java代码,也不要像Java那样编写C++代码。我曾经在一家公司工作过,他们将产品从Java移植到C++,但他们没有像C++那样编写C++代码,导致出现了各种问题,而且难以阅读。

1
谢谢您的回复!我只是希望能够在C ++中编写Viterbi或Baum Welch重新估计算法,并从Android中访问它。仅使用Java编写如此时间关键(它用于实时应用程序)的东西,而且重复相同的算法,这似乎太可惜了。无论如何,感谢您的建议。 - Sonoman
2
实际上,时间关键/性能关键的组件正是您应该为每个设备本地编写的组件类型。(听起来像是您正在编写代码来实现一个隐马尔可夫模型) - Shaggy Frog
1
正确:p 我想我只是试图偷懒,避免重复编写代码。显然,我将原生地为 iPhone 编写代码,但不得不为每个要支持的 Android 设备编写代码,而不仅仅是能够从虚拟机调用代码,这有点麻烦。例如,如果我正在编写一个实现 GAs 来控制 AI 的游戏(我也在做),那么不得不实现两次也有些麻烦,所以我希望有一个简单的解决方案。 - Sonoman
2
懒惰是程序员的一种好品质(这是“三德”之一),但你必须在应用它的时候要实事求是。不想要重复编写代码是一种好态度。然而,当你因为试图为两种完全不同的语言编写一组代码而跳过巨大的障碍时,那么这种努力是得不偿失的。 - Shaggy Frog
14
我对这个答案进行了负面评价,因为我认为它忽略了使用 NDK 的好处。在 Android 应用程序中,唯一必须用 Java 编写的部分是使用 Android 库的部分。如果 UI 交互和/或像网络通信这样的内容占据了大部分代码库,那么我同意你使用 C++ 是在自断后路。但是对于只有薄薄的 UI 层覆盖在不依赖特定平台库的后端上的游戏或应用程序,NDK 绝对是最好的选择。Rob 在他的答案中提供了 NDK 的利弊概述。 - Mitch Lindgren

2
“共享代码库在这种情况下确实非常实用。设置和维护它会有一些开销,但主要好处是:1)通过共享常见功能来减少代码量;2)共享公共代码库的错误修复。目前我知道两种路线可供考虑:使用本地c / c ++(以速度换取垃圾回收和每个处理器的目标设定)或使用monodroid / monotouch为每个操作系统的平台功能提供c#绑定(我不确定其成熟程度如何)。如果我正在编写使用3d的游戏,我肯定会使用第一种方法。”

2

我在类似问题上发布了同样的答案,但我认为这与问题相关...

我使用BatteryTech来处理平台抽象和我的项目结构如下:

在我的PC上:

  • gamename - 只包含通用代码

  • gamename-android - 包含大部分BatteryTech的Android特定代码和Android配置,构建器指向gamename项目获取通用代码

  • gamename-win32 - 仅用于Windows构建,使用gamename项目中的代码

在我的Mac上:

  • gamename - 只包含通用代码

  • gamename-ios - iPhone/iPad构建,导入通用代码

  • gamename-osx - OSX本地构建。导入通用代码。

我使用SVN在我的PC和Mac之间共享。我的唯一真正的问题是当我在Windows中将类添加到通用代码库中,然后在Mac上更新以从SVN拉取它们时。XCode没有自动将它们添加到项目中的方法,因此我必须每次手动引入它们,这很麻烦,但并非世界末日。

所有这些都随着BatteryTech一起提供,因此一旦您掌握它,就很容易理解。


2
除了使用C/C++共享so库外,如果要开发跨平台应用程序(如游戏),建议使用基于mono的框架,例如Unity3D。
如果要开发需要本地UI并希望在移动平台之间共享业务逻辑代码的商业应用程序,建议使用嵌入式Lua引擎作为客户端业务逻辑中心。客户端UI仍然是本地的,并获得最佳的UI性能,例如在Android上使用Java,在iOS上使用ObjectC等。逻辑与所有平台共享相同的Lua脚本。因此,Lua层类似于客户端服务(与服务器端服务进行比较)。
-- Anderson Mao, 2013-03-28

1

虽然我自己不使用这些,因为我写的大部分东西无法很好地移植,但我建议使用类似AppceleratorRed Foundry这样的工具来构建基本应用程序,然后可以在任何平台上本地创建。在这些情况下,您不需要编写Objective-C或Java代码,而是使用某种中介。请注意,如果您超出了他们限制您的范围,您将需要编写更接近底层的自己的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接