Embedded Framework を iOS7 以下で使うには

iOS8で導入されたEmbedded Framework ですが、iOS7以下で使うにはどうすればいいでしょうか。

iOS7でもEmbedded Frameworkがしたい

Objective-C で Embedded Frameworkで実装したEmbedded Frameworkは、iOS8からしか使えません。 でもまだまだiOS7対応も必要ですよね。 また、App Extensionに対応したいけど、iOS7対応はおとせない、という場合もあります。 そんな場合には、この方法が使えます。

iOS7でもEmbedded Frameworkをする

まずは、Objective-C で Embedded Frameworkの手順で、iOS8に対応したEmbedded Frameworkを作ってみてください。 上の記事と同じく、メインのアプリターゲットをnews、Embedded Frameworkをweatherとします。

main7 まずは、メインのアプリターゲットのDeployment Targetを7.0に。

lib7 それから、Embedded FrameworkのDeployment Targetも7.0に。

この時点で、ビルドするとエラーになるはずです。

befoer

この時点で実行時のリンクをはずしてしまいましょう。 メインのターゲットの「Build Phases」設定をみてみましょう。 こうなっているはずです。

after 上の画面の「Link Binary With Libraries」から weather.frameworkをはずします。 そして、さらに「Copy Bundle Resouces」に weather.frameworkを追加します。

ここまでくるとだいたいみなさんなにをしたいのかわかってきたと思いますが、これで weather.frameworkはコンパイル時にリンクされず、ただBundleに含まれているだけの状態になります。 これを実行時に動的にロードしてつかっていく、ということですね。

実行時にEmbedded Frameworkをよびだす

さて、ビルド時の設定を変えたら、あとは呼び出し側のコード部分。 ライブラリのヘッダーファイル(weather.h)をよぶのをやめて、実行時にdlopenを使ってFrameworkをよびだす処理にします。

まず、dlopenを使用するために、dlfcn.h をimport。 Frameworkの名前を指定して、ライブラリをロードします。 (指定する名称が "./weather.framework/"ではなくて、"/weather.framework/weather"になることに注意。)

そのあとは、クラス名を直接指定してオブジェクトを生成。そのオブジェクトに performSelectorを使ってメッセージを送信すると、いつもどおりに使えます。

// for dlopen/dlclose
#import <dlfcn.h>

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    // Frameworkをロードする
    void *newframework = dlopen("./weather.framework/weather", RTLD_LAZY);
    
    if (newframework == 0) {
        fprintf(stderr, "Error: %s\n", dlerror());
    }

    // WTInformationクラスを作成
    id loadedClass = [[NSClassFromString (@"WTInformation") alloc] init];
    // メッセージを送る
    [loadedClass performSelector:@selector(logtoday:) withObject:nil withObject:nil];
    
    if (dlclose(newframework) != 0) {
        fprintf(stderr, "Error: %s\n", dlerror());
    }

}

まとめ

うーん、これ、やってはみたものの、結構めんどうくさい処理ですよね。 自分ではやらないだろうな、という気がします……が、実はiOS7でEmbedded Framworkを使いたい場合にはもう一つ選択肢があるんです。

詳しくはをSwift の Embedded Framework と namespaceを見てみてください。