处理Xcode中的私有框架≥7.3 [英] Handling private frameworks in Xcode ≥ 7.3

查看:140
本文介绍了处理Xcode中的私有框架≥7.3的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Xcode 7.3 / iOS 9.3 Apple删除了所有私有框架来自iOS SDK。出于研究目的(不是App Store!)我需要使用私有框架(即 BluetoothManager.framework ,但这也是任何其他私有<的问题/ strong>框架)。

With Xcode 7.3 / iOS 9.3 Apple removed all private frameworks from the iOS SDKs. For research purposes (not App Store!) I need to work with a private framework (namely BluetoothManager.framework, but this is also an issue for any other private frameworks).

因为这些框架不再在iOS SDK中提供,所以如果我的项目试图明确链接到这个框架,我会收到构建(链接器)错误。

Because these frameworks are no longer delivered in the iOS SDKs, I get a build (linker) error if my project attempts to link to this framework explicitly.

长期(呃)期限解决方案的任何想法?

Any ideas for a long(er)-term solution?

推荐答案

你可以通过链接到私有框架动态来解决此问题,而不是在构建时链接的更常见方式。在构建时,需要在开发Mac上存在BluetoothManager.framework,以便链接器能够使用它。通过动态链接,您可以将流程推迟到运行时。在设备上,iOS 9.3仍然存在该框架(当然还有其他框架)。

You can solve this problem by linking to the private framework dynamically, instead of the more common way of linking at build time. At build time, the BluetoothManager.framework would need to exist on your development Mac for the linker to be able to use it. With dynamic linking, you defer the process until runtime. On the device, iOS 9.3 still has that framework present (and the other ones, too, of course).

以下是如何在 Github

1)在Xcode的Project Navigator中,框架,删除对BluetoothManager.framework的引用。无论如何,它可能显示为红色(未找到)。

1) In Xcode's Project Navigator, under the Frameworks, remove the reference to BluetoothManager.framework. It was probably showing in red (not found) anyway.

2)在项目构建设置下,您明确拥有旧的私有框架目录列为框架搜索路径。删除它。如果找不到,请在构建设置中搜索PrivateFrameworks。

2) Under the project Build Settings, you have the old private framework directory explicitly listed as a framework search path. Remove that. Search for "PrivateFrameworks" in the build settings if you have trouble finding it.

3)确保添加所需的实际标题,以便编译器理解这些私有类。我相信你可以获得当前的标题例如。即使从Mac SDK中删除了框架,我相信这个人已经使用了像运行时浏览器这样的工具。在设备上生成头文件。在您的情况下,将BluetoothManager.h和BluetoothDevice.h标头添加到Xcode项目。

3) Make sure to add the actual headers you need, so the compiler understands these private classes. I believe you can get current headers here for example. Even if the frameworks are removed from the Mac SDKs, I believe this person has used a tool like Runtime Browser on the device to generate the header files. In your case, add BluetoothManager.h and BluetoothDevice.h headers to the Xcode project.

3a)注意:生成的标题有时候不要'编译。我不得不在上面的 struct typedef PrivateFrameworks / BluetoothManager.frameworkrel =nofollow noreferrer>运行时浏览器标头,以便构建项目。 Hattip @Alan_s以下。

3a) Note: the generated headers sometimes don't compile. I had to comment out a couple struct typedefs in the above Runtime Browser headers in order to get the project to build. Hattip @Alan_s below.

4)更改您的进口:

#import <BluetoothManager/BluetoothManager.h>

#import "BluetoothManager.h"

5)你在哪里使用私人课程,你我需要首先动态地打开框架。为此,请使用(在MDBluetoothManager.m中):

5) Where you use the private class, you're going to need to first open up the framework dynamically. To do this, use (in MDBluetoothManager.m):

#import <dlfcn.h>

static void *libHandle;

// A CONVENIENCE FUNCTION FOR INSTANTIATING THIS CLASS DYNAMICALLY
+ (BluetoothManager*) bluetoothManagerSharedInstance {
   Class bm = NSClassFromString(@"BluetoothManager");
   return [bm sharedInstance];
}

+ (MDBluetoothManager*)sharedInstance
{
   static MDBluetoothManager* bluetoothManager = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      // ADDED CODE BELOW
      libHandle = dlopen("/System/Library/PrivateFrameworks/BluetoothManager.framework/BluetoothManager", RTLD_NOW);
      BluetoothManager* bm = [MDBluetoothManager bluetoothManagerSharedInstance];
      // ADDED CODE ABOVE
      bluetoothManager = [[MDBluetoothManager alloc] init];
   });
   return bluetoothManager;
}

我拨打了 dlopen 在你的单例方法中,但你可以把它放在其他地方。它只需要在之前被称为任何代码使用私有API类。

I placed the call to dlopen in your singleton method, but you could put it elsewhere. It just needs to be called before any code uses the private API classes.

我添加了一个方便的方法 [MDBluetoothManager bluetoothManagerSharedInstance] 因为你会反复调用它。当然,我确信你可以找到其他的实现方式。重要的细节是这个新方法使用 NSClassFromString()动态实例化私有类。

I added a convenience method [MDBluetoothManager bluetoothManagerSharedInstance] because you'll be calling that repeatedly. I'm sure you could find alternate implementations, of course. The important detail is that this new method dynamically instantiates the private class using NSClassFromString().

6)你到处都是直接调用 [BluetoothManager sharedInstance] ,将其替换为新的 [MDBluetoothManager bluetoothManagerSharedInstance] 调用。

6) Everywhere you were directly calling [BluetoothManager sharedInstance], replace it with the new [MDBluetoothManager bluetoothManagerSharedInstance] call.

我使用Xcode 7.3 / iOS 9.3 SDK对此进行了测试,您的项目在我的iPhone上正常运行。

I tested this with Xcode 7.3 / iOS 9.3 SDK and your project runs fine on my iPhone.

由于似乎有些混淆,这种相同的技术(和确切的代码)仍然适用于iOS 10.0-11.1(截至本文撰写时)。

Since there seems to be some confusion, this same technique (and exact code) still works in iOS 10.0-11.1 (as of this writing).

此外,强制加载框架的另一个选项是使用 [NSBundle bundleWithPath:] 而不是 dlopen()。但请注意路径的细微差别:

Also, another option to force loading of a framework is to use [NSBundle bundleWithPath:] instead of dlopen(). Notice the slight difference in paths, though:

handle = dlopen("/System/Library/PrivateFrameworks/BluetoothManager.framework/BluetoothManager", RTLD_NOW);
NSBundle *bt = [NSBundle bundleWithPath: @"/System/Library/PrivateFrameworks/BluetoothManager.framework"];

这篇关于处理Xcode中的私有框架≥7.3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆