iOS App中實(shí)現(xiàn)可拆卸一個(gè)framework的“兩”種方式

此處說(shuō)的可拆卸凿可,意思就是業(yè)務(wù)App的工程是否導(dǎo)入這個(gè)framework都不影響編譯。如果業(yè)務(wù)導(dǎo)入了這個(gè)framework涉馅,就可以使用其中功能归园,如果沒(méi)導(dǎo)入,也能編譯通過(guò)稚矿。

1. 應(yīng)用場(chǎng)景

在我們開(kāi)發(fā)項(xiàng)目的過(guò)程中庸诱,會(huì)導(dǎo)入很多的三方庫(kù),比如:會(huì)導(dǎo)入公司內(nèi)部業(yè)務(wù)封裝的晤揣、微信桥爽、微博和支付寶等相關(guān)的framework等。在稍微復(fù)雜一點(diǎn)的業(yè)務(wù)中昧识,如下圖:

其中钠四,A.framework和B.framework都是靜態(tài)庫(kù),A.framework使用了B.framework中的方法跪楞,那么缀去,一般情況下在APP中想要使用A.framework中的方法,必須要同時(shí)將A.framework和B.framework導(dǎo)入到APP工程中习霹,否則編譯時(shí)會(huì)報(bào)錯(cuò)朵耕。但是在現(xiàn)實(shí)情況中,可能業(yè)務(wù)不需要A包中涉及到B包的功能淋叶,因此只想導(dǎo)入A.framework且不想導(dǎo)入B.framework阎曹。

我們新建了一個(gè)下面的工程,工程中有兩個(gè)framework煞檩,示例中APP直接使用TestDynamicSdk的方法处嫌,TestDynamicSdk使用TestStaticSdk的方法。

2. 使用相應(yīng)的宏

以下代碼工作在APP的Test類中:

#import "Test.h"

//// __has_include() 宏在導(dǎo)入三方庫(kù) .h 過(guò)程中的使用
#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


@interface Test ()

@property (nonatomic, strong) id staticSdkObject;

@end

@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

注意:使用__has_include宏的方式在使用TestDynamicSdk時(shí)斟湃,來(lái)實(shí)現(xiàn)自由拆卸TestStaticSdk.framework熏迹,是行不通的。宏在編譯時(shí)就已經(jīng)被展開(kāi)替換凝赛,即在A.framwork編譯的時(shí)就已經(jīng)決定了B.framwork是否導(dǎo)入注暗。__has_include這個(gè)宏只能在APP層中坛缕,實(shí)現(xiàn)代碼上的容錯(cuò)

3. 使用運(yùn)行時(shí)相關(guān)方法

以下代碼工作在TestDynamicSdk中捆昏,我們以TestDynamicSdk作為上述A.framework的角色做說(shuō)明:

#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沒(méi)有編譯");
            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:方法沒(méi)有實(shí)現(xiàn)");
        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

這樣能實(shí)現(xiàn)APP在使用TestDynamicSdk時(shí)赚楚,自由拆卸TestStaticSdk.framework。

注意骗卜,SEL和IMP的區(qū)別宠页,
函數(shù)具體實(shí)現(xiàn)的指針I(yè)MP定義: typedef id (*IMP)(id, SEL, );
可以從對(duì)象 & SEL的方法得到:IMP imp = [self methodForSelector:selector];

// NSObject里面的這兩個(gè)方法:
- (IMP)methodForSelector:(SEL)aSelector;
+ (IMP)instanceMethodForSelector:(SEL)aSelector;

// 無(wú)參方法調(diào)用
Class class = NSClassFromString(@"classA");
SEL selector = NSSelectorFromString(@"方法名");
IMP imp = [class methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(class, selector);
 
// 有參有返回值方法調(diào)用
SEL selector = NSSelectorFromString(@"方法名");
IMP imp = [self methodForSelector:selector];
id (*func)(id, SEL,NSString *, NSArray *) = (void *)imp; //id (*)(id, SEL,NSString *, NSArray *) 應(yīng)該強(qiáng)轉(zhuǎn)這個(gè)吧?寇仓?
id ret = func(self, selector,@"1",@[@"1",@"2"]);

// 調(diào)用self自身方法举户,可直接用msgSend
SEL testFunc = NSSelectorFromString(@"testRuntime");
((void(*)(id,SEL, id,id))objc_msgSend)(self, testFunc, nil, nil);

PS:

  1. 在用宏定義實(shí)現(xiàn)時(shí)編譯可能會(huì)報(bào)錯(cuò),開(kāi)發(fā)TestDynamicSdk時(shí)需要在其工程配置中添加TestStaticSdk.framework遍烦;
  2. 使用運(yùn)行時(shí)相關(guān)方法實(shí)現(xiàn)時(shí)俭嘁,需要在APP的工程配置中設(shè)置-all_load。

參考文章:iOS 利用 Framework 進(jìn)行動(dòng)態(tài)更新

GitHub源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末服猪,一起剝皮案震驚了整個(gè)濱河市兄淫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔓姚,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慨丐,死亡現(xiàn)場(chǎng)離奇詭異坡脐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)房揭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門备闲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人捅暴,你說(shuō)我怎么就攤上這事恬砂。” “怎么了蓬痒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵泻骤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我梧奢,道長(zhǎng)狱掂,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任亲轨,我火速辦了婚禮趋惨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惦蚊。我一直安慰自己器虾,他們只是感情好讯嫂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著兆沙,像睡著了一般欧芽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挤悉,一...
    開(kāi)封第一講書(shū)人閱讀 51,215評(píng)論 1 299
  • 那天渐裸,我揣著相機(jī)與錄音,去河邊找鬼装悲。 笑死昏鹃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诀诊。 我是一名探鬼主播洞渤,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼属瓣!你這毒婦竟也來(lái)了载迄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抡蛙,失蹤者是張志新(化名)和其女友劉穎护昧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體粗截,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惋耙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熊昌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绽榛。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖婿屹,靈堂內(nèi)的尸體忽然破棺而出灭美,到底是詐尸還是另有隱情,我是刑警寧澤昂利,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布届腐,位于F島的核電站,受9級(jí)特大地震影響蜂奸,放射性物質(zhì)發(fā)生泄漏梯捕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一窝撵、第九天 我趴在偏房一處隱蔽的房頂上張望傀顾。 院中可真熱鬧,春花似錦碌奉、人聲如沸短曾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嫉拐。三九已至哩都,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間婉徘,已是汗流浹背漠嵌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盖呼,地道東北人儒鹿。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像几晤,于是被迫代替她去往敵國(guó)和親约炎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容