如何 运行 2 个嵌入式不同项目中的一个项目
How to run a project out of 2 embedded different project
我有两个 iOS 项目,我想将其作为一个项目,并根据条件一次 运行 一个项目。
例如:我有 2 个名为 ProjectA 和 ProjectB 的项目。我想将 ProjectA 和 ProjectB 嵌入到名为 ProjectC 的单个项目中。
ProjectC 将有一个条件,具体取决于我必须 运行 projectA 或 ProjectB[=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
你总是可以做 ProjectAAppDelegate
和 ProjectBAppDelegate
.
- 检查
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) {}
这就是我所说的提前制定策略的意思。策略示例:
- ProjectA 是 "winner",因此只有 ProjectB 会有变化
- ProjectB 是 "winner",因此只有 ProjectA 会有变化
- 项目 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 分支。我经常只是复制实际的目录,以便以后需要时可以比较它们。
我有两个 iOS 项目,我想将其作为一个项目,并根据条件一次 运行 一个项目。
例如:我有 2 个名为 ProjectA 和 ProjectB 的项目。我想将 ProjectA 和 ProjectB 嵌入到名为 ProjectC 的单个项目中。 ProjectC 将有一个条件,具体取决于我必须 运行 projectA 或 ProjectB[=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
你总是可以做ProjectAAppDelegate
和ProjectBAppDelegate
. - 检查
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) {}
这就是我所说的提前制定策略的意思。策略示例:
- ProjectA 是 "winner",因此只有 ProjectB 会有变化
- ProjectB 是 "winner",因此只有 ProjectA 会有变化
- 项目 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 分支。我经常只是复制实际的目录,以便以后需要时可以比较它们。