如何从两个不同的嵌入式项目中运行一个项目



我有两个iOS项目,我想把它作为一个单独的项目,并根据条件一次运行一个项目。

例如:我有两个名为ProjectAProjectB的项目。我想将ProjectArojectBrojectCrojectC将有一个条件,这取决于我必须运行projectAProjectB代码的条件。

注意:运行项目的条件将在运行时应用,而不是在编译时应用。

我怀疑这真的可能吗?我需要如何处理这个问题的专业指导。

我建议您创建pod并调用您的项目,您可以根据场景/用例进行调用,这样您就可以在pod中保留任意数量的项目。

您可以参考此链接。

另一种方法是让你的两个项目走在同一条路上,创建动态框架,并将这些引用用于项目"C"。我指的是你为计划的新项目

任何一种方法都可以解决你的问题。

好的,根据阅读问题并提出一些问题。。。我真的不清楚为什么pods的答案得到了这么多选票。它不能解决问题。

假设我们有现有的项目A和项目B。ProjectC还不存在,但我们希望使ProjectC成为a和B的"组合",其中a或B将基于某种条件运行。一旦运行,该应用程序将一直运行该版本,直到重新启动。

两种基本方法是将所有代码和资产组合到ProjectC中,或者尝试制作您加载的A和B框架。但是,对于这两种情况,您都必须对代码库进行调整。你需要做的工作量也是项目复杂程度的副产品。

我参与过一个项目,我们成功地实现了您对大型应用程序的需求。我们通过iPhone和iPad项目,结合代码/资产,基本上制作了一个"通用应用程序"。我们在运行时"启动"了相应的版本。

在你付出这样的努力之前,你需要权衡一下后果。我会列出一些。

  • 如果您的A/B依赖于bundle id,那么您将遇到问题。ProjectC将有自己的捆绑id。例如,是否有任何第三方API(如Facebook)在使用中,您希望仍然使用它们,并且看起来像ProjectA或ProjectB?如果是,但它们与捆绑id绑定,则会出现问题
  • 如果您正在使用IAP,您的产品ID将需要有所不同。因此,很明显,如果这些产品ID是硬编码的,那么A和B中的代码将需要更改。如果它们是服务器驱动的,您需要确保服务器代码并实际提供正确的产品ID。如果期望ProjectA的所有者仍然拥有ProjectC的IAP,这是可能的。。。然而,成本来自于需要与您的规模相适应的服务器端逻辑来管理这一点
  • 调试代码时需要付出多少努力
  • 项目A和项目B仍在积极开发中吗?这样做可能会使这些项目在以后很难维护
  • 为此将留出多少时间?这样做既乏味又耗时

您可能会更成功地将A和B的源/资产组合到C中。换句话说,您不会将A或B的项目文件添加到C中,为什么?因为你需要能够轻松识别所有冲突点,然后提供解决方案。冲突的一个简单例子是AppDelegate,它是项目默认创建的。你会有三个(A、B、C)。

请记住,所有方法都充满了问题。如果你选择框架(不管它们是否是Pod),并且你决定你的资产进入框架捆绑包,你必须更改代码才能访问它们,因为它们不再在mainBundle中。

好吧,一般的指导方针是什么?

  • 选择一种方法(例如组合或框架)。我将讨论联合收割机
  • 提前确定尽可能多的冲突。针对每种类型的冲突,确定您的策略。例如,要求解AppDelegate,您可以始终执行ProjectAAppDelegateProjectBAppDelegate
  • 检查Info.plist。这是其他冲突的一个很好的来源。C的Info.plist将是两者的组合
  • 想出一个如何处理冲突的策略。例如,我们有一个命名约定,当类名冲突时,我们会使用它
  • 将您的ProjectA和ProjectC源代码/资产添加到Project C中。开始修复冲突
  • 喝很多咖啡

你需要控制的另一件关键事情是基于决策的切入点。如果您可以在main.m中调用UIApplicationMain之前做出决定,您可以执行以下操作:

Class appDelegate;
if (runA) {
appDelegate = [ProjectAAppDelegate class];
} else {
appDelegate = [ProjectBAppDelegate class];
}
return UIApplicationMain(argc, argv, nil, NSStringFromClass(appDelegate));

如果这不起作用,那么您将不得不在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中执行此操作。然后你可能想要让项目C的AppDelegate作为a和B的代理。例如:

- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
[self.projectAppDelegate applicationDidBecomeActive:application];
}

其中projectAppDelegate设置为您需要的正确版本。

请注意,您还需要手动加载情节提要,以确保启动正确的情节提要。请记住,如果你在加载过程中花费太多时间做出决定(你说这是一个网络呼叫),你的应用程序可以启动。

如果它们是框架的话,你可能会找到一些漂亮的动态加载,但关键应该是可维护性/易于调试。

我将在这里停下来,主要是因为有太多不同的事情要做,我真的没有时间把它们都写出来。

Additional info based on follow up question

文件重复的可能性很高。我举了AppDelegate的例子。enum将不那么频繁,但会发生。还要记住,您关心的不是文件名,而是类或其他定义的数据类型。这些是对编译器/链接器很重要的冲突。

例如:

项目A:

typedef NS_ENUM(NSInteger, State) {}

项目B:

typedef NS_ENUM(NSInteger, State) {}

这就是我提前制定战略的意思。示例策略:

  1. 项目A是"赢家",因此只有项目B会有变化
  2. ProjectB是"赢家",因此只有ProjectA会有变化
  3. 项目A和项目B都将发生变化

所以对于1,结果将是

项目A:

typedef NS_ENUM(NSInteger, State) {}

项目B:

typedef NS_ENUM(NSInteger, PBState) {}

注意我听到的。为了让我的生活更轻松,我使用了一些预定义的前缀来指定它为ProjectB。在这种情况下,PB。

对于2:项目A:

typedef NS_ENUM(NSInteger, PAState) {}

项目B:

typedef NS_ENUM(NSInteger, State) {}

对于3:项目A:

typedef NS_ENUM(NSInteger, PAState) {}

项目B:

typedef NS_ENUM(NSInteger, PBState) {}

这将由你来制定规则,但要保持一致。您将需要一个如何解决所有数据类型更改的策略。例如,如果您要从State->PBState,那么您显然只想修改ProjectB。以下是在自己的项目中使用它会有所帮助的地方。但是,您可以使用Xcode的Search Scope来帮助控制这种情况。

哦,还有一些其他的事情。

首先,投资一个脚本来查找ProjectA和ProjectB中的所有重复文件。基本上,您需要根据需要的扩展(例如.m、.h、.xib等)在ProjectA和ProjectB上执行find。这将给你一份潜在候选人的名单,从中你可以制定规则。

由于我是做这部分项目的傻瓜,所以我基本上把这个列表保存在一个文本文件中。当我合并该文件时,我将其移动到文件中的另一个部分(用几行换行符分隔)。有不同的会计方法,这只是我选择的方法。

我也会确保你有一个好的diff工具,比如Araxis Merge(这就是我使用的)。

此外,经常拍摄快照以防万一。您可以使用git分支。我经常只是复制实际的目录,这样以后如果需要的话我可以对它们进行比较。

最新更新