Xcode 7.3/iOS9.3ではAppleすべてのプライベートフレームワークを削除 iOS SDKから。調査目的(App Storeではありません!)では、プライベートフレームワークを使用する必要があります(つまり、BluetoothManager.framework
ですが、これは他のprivateフレームワークの問題でもあります。
これらのフレームワークはiOSSDKで提供されなくなったため、プロジェクトがこのフレームワークに明示的にリンクしようとすると、ビルド(リンカー)エラーが発生します。
長期的な解決策について何かアイデアはありますか?
ビルド時でリンクするより一般的な方法の代わりに、プライベートフレームワーク動的にリンクすることで、この問題を解決できます。ビルド時に、リンカーがBluetoothManager.frameworkを使用できるようにするには、開発用MacにBluetoothManager.frameworkが存在する必要があります。ダイナミックリンクを使用すると、実行時までプロセスを延期できます。デバイス上では、iOS 9.3にはまだそのフレームワークが存在します(もちろん、他のフレームワークも存在します)。
Github でプロジェクトを変更する方法は次のとおりです。
1)Xcodeのプロジェクトナビゲータの[フレームワーク]で、BluetoothManager.frameworkへの参照を削除します。とにかく、おそらく赤で表示されていました(見つかりませんでした)。
2)プロジェクトビルド設定の下に、フレームワーク検索パスとして明示的にリストされた古いプライベートフレームワークディレクトリがあります。それを削除します。見つからない場合は、ビルド設定で「PrivateFrameworks」を検索してください。
3)コンパイラがこれらのプライベートクラスを理解できるように、必要な実際のヘッダーを必ず追加してください。私はあなたが現在のヘッダーを得ることができると信じています 例えばここで 。フレームワークがMacSDKから削除されたとしても、この人はデバイス上で ランタイムブラウザ のようなツールを使用してヘッダーファイルを生成したと思います。あなたの場合、BluetoothManager.hおよびBluetoothDevice.hヘッダーをXcodeプロジェクトに追加します。
3a)注:生成されたヘッダーがコンパイルされない場合があります。プロジェクトをビルドするために、上記のstruct
typedefをいくつかコメントアウトする必要がありました ランタイムブラウザヘッダー 。以下のハットチップ@Alan_s。
4)インポートを次の場所から変更します。
_#import <BluetoothManager/BluetoothManager.h>
_
に
_#import "BluetoothManager.h"
_
5)プライベートクラスを使用する場合、最初にフレームワークを動的に開く必要があります。これを行うには、(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クラスを使用する前に呼び出す必要があります。
繰り返し呼び出すので、便利なメソッド_[MDBluetoothManager bluetoothManagerSharedInstance]
_を追加しました。もちろん、別の実装を見つけることができると確信しています。重要な詳細は、この新しいメソッドがNSClassFromString()
を使用してプライベートクラスを動的にインスタンス化することです。
6)_[BluetoothManager sharedInstance]
_を直接呼び出していた場所はすべて、新しい_[MDBluetoothManager bluetoothManagerSharedInstance]
_呼び出しに置き換えます。
これをXcode7.3/iOS 9.3 SDKでテストしたところ、プロジェクトはiPhoneで正常に実行されます。
多少の混乱があるように思われるので、これと同じ手法(および正確なコード)はiOS 10.0-11.1でも機能します(この記事の執筆時点)。
また、フレームワークのロードを強制する別のオプションは、dlopen()
の代わりに_[NSBundle bundleWithPath:]
_を使用することです。ただし、パスのわずかな違いに注意してください。
_handle = dlopen("/System/Library/PrivateFrameworks/BluetoothManager.framework/BluetoothManager", RTLD_NOW);
NSBundle *bt = [NSBundle bundleWithPath: @"/System/Library/PrivateFrameworks/BluetoothManager.framework"];
_