ios - Objective-C 框架和命名空间冲突

标签 ios objective-c ios-frameworks

我们希望将 2 个版本的 iOS 应用程序放在同一个包中。这样我们的客户就可以在推送更新后恢复到旧版本。我本来希望通过将当前版本和以前的版本构建到框架中并在提示用户后调用适当的版本来实现这一目标。

作为测试,我创建了两个框架,LibA 和 LibB,每个框架都包含 Thing 类。

我遇到的问题是这个运行时警告...

objc[21117]:类事物在/private/var/containers/Bundle/Application/0E6374C5-52FB-421F-90D6-ADC9A4C22B5D/DualBootTestApp.app/Frameworks/LibA.framework/LibA 中实现( 0x102b144b0)和/private/var/containers/Bundle/Application/0E6374C5-52FB-421F-90D6-ADC9A4C22B5D/DualBootTestApp.app/Frameworks/LibB.framework/LibB(0x102ba4460)。将使用两者之一。哪一个未定义。

在现实世界中,这些框架将是同一应用程序的两个版本,因此每个框架中 99% 的类名都是相同的。

每个框架实际上都会调用自己的 Thing 版本,但运行时警告表明我不能依赖这种行为。

更新

我刚刚尝试使用 Cocoa Touch 静态库。使用静态库时,我不会收到运行时警告,但始终会调用 LibB 中的 Thing 类版本,即使调用源自 LibA。

我开始相信某种为 objective-c 类名称添加前缀的宏可能是唯一的解决方案。大量共享代码使这一前景黯淡。

有谁知道如何隐藏类名,以便只有每个框架都可以看到自己的类?

是否有更好的方法将应用程序的两个版本添加到同一个 bundle 中?有可能吗? Appstore 审核会出现问题吗?

最佳答案

如果您已经将类放入框架中,那么恭喜您,您已经完成了最困难的部分。但请记住,如果您的大部分应用程序代码都在框架中,则某些事情可能不会按预期运行。例如,假设您也对 Assets 进行了版本控制,则任何最终调用 NSBundle.mainBundle 的代码(例如 +[UIImage imageNamed:])都可能是错误的。

但我们假设您已成功框架化您的应用版本。

如果您想在运行时选择其中一个框架,则无法链接到任一框架。相反,您需要使用 dlopenNSClassFromStringdlsym 来到达入口点。

这是一个例子:

#import <dlfcn.h>
#import "HeaderWithEntryPointMethod.h"

void pickedAppVersion(int version) {
    NSString *frameworkName = [NSString stringWithFormat:@"AppV%d", version];
    NSString *frameworkExecutable = [NSString stringWithFormat:@"%@.framework/%@", frameworkName, frameworkName]; // this should traverse the symlink 
    NSString *frameworkPath = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:frameworkExecutable];
    void *frameworkHandle = dlopen(frameworkPath.UTF8String, RTLD_NOW);
    if (frameworkHandle != NULL) {
        Class EntryPointClass = NSClassFromString(@"EntryPoint");
        assert(EntryPointClass != Nil);
        [EntryPointClass entryMethod];
        // App framework should do everything from here
        if (dlclose(frameworkHandle) != 0) {
            NSLog(@"failed to close chosen app framework: %s", dlerror());
        }
    }
    else {
        NSLog(@"failed to open app framework: %@ because: %s", frameworkName, dlerror());
    }
}

至于 EntryPoint+entryMethod 到底是什么,这取决于您。如果您需要 C 函数入口点,请使用 dlsym 而不是 NSClassFromString

回复:App Store 评论:我想这可能会引起一两个人的注意,但只要你允许用户,特别是评论者进行选择,就不应该有问题。 dlopen 通常用于在运行时有选择地加载框架,以简化应用程序启动和加载应用程序按需使用的功能。

关于ios - Objective-C 框架和命名空间冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60266482/

相关文章:

ios - NSArray 的大小

ios - 来自 iOS 静态框架的“无法在 bundle 中加载 NIB”

ios - Swift 3,框架 IBOutlet 属性始终展开可选

android - 除了蓝牙之外,还有其他跨平台离线发送数据的方法吗?

ios - 可以将.mobi文件与Xcode一起使用来为App Store创建应用程序吗?

ios - 保存到相机胶卷 - 不支持此电影格式

objective-c - 如何从搜索字段获取文本?

objective-c - 将 Objective-C 中字符串中的整数相加

ios - 无法在设备 : iOS 9 frameworks won't codesign 上运行应用程序

iOS – 在特定时间在后台上传