iOS App中可拆卸一個framework的兩種方式

QiShare發表於2019-11-11

級別: ★☆☆☆☆
標籤:「iOS」「framework」
作者: dac_1033
審校: QiShare團隊


此處說的可拆卸,意思就是業務App的工程是否匯入這個framework都不影響編譯。如果業務匯入了這個framework,就可以使用其中功能,如果沒匯入,也能編譯通過。

1. 應用場景

在我們開發專案的過程中,會匯入很多的三方庫,比如:會匯入公司內部業務封裝的、微信、微博和支付寶等相關的framework等。在稍微複雜一點的業務中,如下圖:

iOS App中可拆卸一個framework的兩種方式

其中,A.framework和B.framework都是靜態庫,A.framework使用了B.framework中的方法,那麼,一般情況下在APP中想要使用A.framework中的方法,必須要同時將A.framework和B.framework匯入到APP工程中,否則編譯時會報錯。但是在現實情況中,可能業務不需要A包中涉及到B包的功能,因此只想匯入A.framework且不想匯入B.framework。

我們新建了一個下面的工程,工程中有兩個framework,示例中APP直接使用TestDynamicSdk的方法,TestDynamicSdk使用TestStaticSdk的方法。

iOS App中可拆卸一個framework的兩種方式

2. 使用相應的巨集

以下程式碼工作在TestDynamicSdk中,我們以TestDynamicSdk作為上述A.framework的角色做說明:

#import "TestDynamicSdk.h"

//// __has_include() 巨集在匯入三方庫 .h 過程中的使用
#if __has_include(<TestStaticSdk/TestStaticSdk.h>)
    #import <TestStaticSdk/TestStaticSdk.h>
    #ifndef HAS_IMPORT_DY
        #define HAS_IMPORT_DY 1
    #endif
#else
    #ifndef HAS_IMPORT_DY
        #define HAS_IMPORT_DY 0
    #endif
#endif

@implementation TestDynamicSdk

//// ?上面定義的巨集HAS_IMPORT_DY的使用
- (NSString *)getCombineStrWithA:(NSString *)aStr B:(NSString *)bStr {

#if HAS_IMPORT_DY == 1
    TestStaticSdk *staticSdk = [[TestStaticSdk alloc] init];
    NSString *combinedStr = [staticSdk getCombineStrWithA:@"common_A_String" B:@"common_B_String"];
    return combinedStr;
#else
    return nil;
#endif
}

@end
複製程式碼

這樣APP即可在使用TestDynamicSdk時自由拆卸TestStaticSdk.framework。

3. 使用執行時相關方法

#import "TestDynamicSdk.h"

@interface TestDynamicSdk ()

@property (nonatomic, strong) id staticSdkObject;

@end

@implementation TestDynamicSdk

- (id)init {
    
    self = [super init];
    if (self) {
        
        Class class = NSClassFromString(@"TestStaticSdk");
        if (!class) {
            NSLog(@"TestStaticSdk沒有編譯");
            return self;
        }
        SEL sel = NSSelectorFromString(@"new");
        id (*imp)(id, SEL) = (id (*)(id, SEL))[class methodForSelector:sel];
        self.staticSdkObject = imp(class, sel);
    }
    return self;
}

- (NSString *)getCombineStrWithA:(NSString *)aStr B:(NSString *)bStr {

    if (!_staticSdkObject) {
        NSLog(@"staticSdkObject為空");
        return nil;
    }
    SEL sel = NSSelectorFromString(@"getCombineStrWithA:B:");
    if (![_staticSdkObject respondsToSelector:sel]) {
        NSLog(@"getCombineStrWithA:B:方法沒有實現");
        return nil;
    }
    NSString * (*imp)(id, SEL, NSString *, NSString *) = (NSString * (*)(id, SEL, NSString *, NSString *))[_staticSdkObject methodForSelector:sel];
    NSString *combinedStr = imp(_staticSdkObject, sel, aStr, bStr);
    return combinedStr;
}

@end
複製程式碼

這樣也能實現APP在使用TestDynamicSdk時自由拆卸TestStaticSdk.framework。

注意:

  1. 在用巨集定義實現時編譯可能會報錯,開發TestDynamicSdk時需要在其工程配置中新增TestStaticSdk.framework;
  2. 使用執行時相關方法實現時,需要在APP的工程配置中設定-all_load。

GitHub原始碼


瞭解更多iOS及相關新技術,請關注我們的公眾號:

iOS App中可拆卸一個framework的兩種方式

小編微信:可加並拉入《QiShare技術交流群》。

iOS App中可拆卸一個framework的兩種方式

關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)

推薦文章:
自定義WKWebView顯示內容(一)
Swift 5.1 (6) - 函式
Swift 5.1 (5) - 控制流
Xcode11 新建工程中的SceneDelegate
iOS App啟動優化(二)—— 使用“Time Profiler”工具監控App的啟動耗時
iOS App啟動優化(一)—— 瞭解App的啟動流程
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合型別
奇舞週刊

相關文章