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

How to run a project out of 2 embedded different project

我有两个 iOS 项目,我想将其作为一个项目,并根据条件一次 运行 一个项目。

例如:我有 2 个名为 ProjectAProjectB 的项目。我想将 ProjectAProjectB 嵌入到名为 ProjectC 的单个项目中。 ProjectC 将有一个条件,具体取决于我必须 运行 projectAProjectB[=29= 的条件]代码。

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

我怀疑这真的可能吗?我需要有关如何解决此问题的专业指导。

我建议您创建 pods 并调用您的项目,您可以根据 scenario/use-case 调用它,这样您可以在 pods 中保留任意数量的项目。

你可以参考这个link

另一种方法是让你的两个项目保持相同的路径,创建动态框架并将这些引用用于项目'C'我的意思是你正在计划的新项目

任何一种方法都应该可以解决您的问题。

好的,基于阅读问题并提出一些问题...我真的不清楚为什么关于 pods 的答案获得了如此多的选票。没有解决问题。

假设我们有现有的 ProjectA 和 ProjectB。 ProjectC 尚不存在,但希望根据某些条件使 ProjectC 成为 A 和 B 的 "combination",其中 A 或 B 将 运行。一旦 运行,应用程序将保持 运行 那个版本,直到重新启动。

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

我参与过一个项目,我们成功地完成了大型应用程序的要求。我们通过 iPhone 和 iPad 项目结合了 code/assets,本质上创造了一个 "universal app"。我们 "launched" 在 运行 时发布了合适的版本。

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

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

您可能会更成功地将 A 和 B 的 source/assets 组合到 C 中。换句话说,您不会 添加 A 或 B 的项目文件进入C。为什么?因为您需要能够轻松识别所有冲突点,然后提供解决方法。冲突的一个简单示例是 AppDelegate,这是项目默认创建的。您将拥有其中的 3 个(A、B、C)。

请记住,所有的方法都充满了问题。如果您选择框架(无论它们是否 Pods)并且您决定将您的资产放入框架包中,您必须更改代码以访问它们,因为它们不再在 mainBundle.

好的,一般准则是什么?

  • 选择一种方法(例如组合或框架)。我要讨论合并。
  • 预先确定尽可能多的冲突。针对每种类型的冲突确定您的策略。例如,要解决 AppDelegate 你总是可以做 ProjectAAppDelegateProjectBAppDelegate.
  • 检查 Info.plist。这是其他冲突的一个很好的来源。 C 的 Info.plist 将是两者的组合。
  • 想出一个处理冲突的策略。例如,当我们有 class 个冲突的名称时,我们会使用一个命名约定。
  • 将您的项目 A 和项目 C 源 code/asset 添加到项目 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 设置为您需要的正确版本。

请注意,您还需要手动加载故事板以确保启动正确的故事板。请记住,如果您在加载过程中花费大量时间做出决定(您说这是网络调用),您的应用程序可以启动。

如果它们是框架,您也许可以找到一些漂亮的动态加载,但关键应该是 maintainability/ease 调试。

我要说到这里主要是因为有很多不同的事情要做,我真的没有时间把它们都写出来。

Additional info based on follow up question

您有一些文件重复的可能性很高。我举了AppDelegate的例子。 enum 会不那么频繁,但会发生。还要记住,这不是您关心的文件名,而是您关心的 class 或其他定义的数据类型。这些是对 compiler/linker.

重要的冲突

例如说:

项目A:

typedef NS_ENUM(NSInteger, State) {}

项目 B:

typedef NS_ENUM(NSInteger, State) {}

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

  1. ProjectA 是 "winner",因此只有 ProjectB 会有变化
  2. ProjectB 是 "winner",因此只有 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。这将为您提供潜在候选人的列表,您可以从中制定规则。

由于我是完成这部分项目的傻瓜,所以我基本上将此列表保存在文本文件中。当我合并文件时,我将它移动到文件中的不同部分(由几个换行符分隔)。有不同的方式来计算它,它只是我选择的方法。

我还会确保您拥有像 Araxis Merge(我用过的)这样的好 diff 工具。

另外,经常拍快照以防万一。您可以使用 git 分支。我经常只是复制实际的目录,以便以后需要时可以比较它们。