iOS App中可拆卸一个framework的两种方式

级别: ★☆☆☆☆
标签:「iOS」「framework」
作者: dac_1033
审校: QiShare团队


此处说的可拆卸,意思就是业务App的工程是否导入这个framework都不影响编译。如果业务导入了这个framework,就可以使用其中功能,如果没导入,也能编译通过。

1. 应用场景

在我们开发项目的过程中,会导入很多的三方库,比如:会导入公司内部业务封装的、微信、微博和支付宝等相关的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的方法。

2. 使用相应的宏

以下代码工作在APP层代码中:

#import "Test.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 Test

//// 👆上面定义的宏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宏可以在APP层实现自由拆卸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源码https://github.com/QiShare/QiTestFramework.git)


了解更多iOS及相关新技术,请关注我们的公众号:

小编微信:可加并拉入《QiShare技术交流群》。

关注我们的途径有:
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) - 集合类型
奇舞周刊

推荐阅读更多精彩内容

  • 此处说的可拆卸,意思就是业务App的工程是否导入这个framework都不影响编译。如果业务导入了这个framew...
    大成小栈阅读 191评论 2 3
  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 6,641评论 0 4
  • 昨天的小惊喜,原来2018年的自己许下了那些愿望。 大部分做到了,一部分自己也会努力的去做好,剩下的这几天一定会努...
    幸运的JoanJoan阅读 11评论 0 0
  • 书法是瞬间的艺术,用的却是一生功夫。看似简单的写字,但一点一画都需要长年累月的练习,书写时方能一挥而就,一气呵成。
    史介鸿阅读 165评论 0 2
  • 2018年2月2日 今天星期5,儿子放假了。回家开门就看到儿子在沙发上看书,是喜欢的《米小圈》。看他看的认真的劲,...
    王海瑞妈妈阅读 22评论 0 1