iOS组件化实践之:资源组件库

Posted by PaysonChen on July 26, 2023

iOS组件化实现之:资源组件库

1 资源有哪些

​ 笼统的可以说,只要不是代码文件的,都可以算是资源文件,举些例子,包括但不限于:图片、音频、视频、动画、字体、多语言文件(.strings)、各类资源包、内置数据库、二进制加密文件不等

2 为什么要做

​ 存在一些可复用的资源,举些例子,包括但不限于:

  • 通用样式图标

    导航条图标、头像、按钮、单/复选框、通用背景图片等

  • 通用媒体文件

    通用的点击音效、提示音、过场动画、加载动画等

  • 其他通用文件

    城市列表、字体、第三方预置资源等

由于部分资源是有通用性,因此将这些通用资源提取出来,形成组件,可服务于更多项目,提升集成的效率,降低研发成本

3 怎么做

3.1 新建一个Pod私有库

此处省略一万字(查看另一篇文章)

3.2 迁移主工程资源

主工程:

中的资源一般散落在各处,即遍是不一定全部存放在asset集合中,可以通过Xcode Project Navigator底部的搜索栏,通过后缀名(.png / .jpg /.webp /.mp3 /,mp4 ……)检索出资源

资源组件库:

asset文件夹下存放主工程迁移的资源。

存放形式可以以下形式:

  • xcassets集合
  • 散落的资源文件

配置podspec:

通过指定resource_bundles进行资源的配置

1
2
3
4
5
6
7
   s.resource_bundles = {
     'PSCResource' => [
     'PSCResource/Assets/PSCCommon.xcassets',
     'PSCResource/Assets/PSCCommonResources/**/*',
     'PSCResource/Assets/XXProj.xcassets',
     'PSCResource/Assets/XXProjResources/**/*']
   }

3.3 资源读取方式

资源组件化之前,使用一般是

//图片:imageNamed
[UIImage imageNamed:@"pic"];

//资源:通过mainBundle进行:
[[NSBundle mainBundle] pathForResource:@"name" ofType:@"ext"];

这是因为,主工程里的资源,一般是打包到xx.app的根目录(xcasset以asset.car存在)

组件库里的资源是打包 xx.framework/xx.bundle

1
2
3
……/Debug-iphoneos/xxx.app/Frameworks/xx.framework/xx.bundle/pic.png
……/Debug-iphoneos/xxx.app/Frameworks/xx.framework/xx.bundle/asset.car
……

直接通过下列方法获取为空

//组件库资源,通过以下方法获取为nil
[UIImage imageNamed:@"pic"];
[[NSBundle mainBundle] pathForResource:@"name" ofType:@"ext"];

组件库资源获取方法是为下列类添加类别

  • UIImage:
@interface UIImage (PSCResource)

/// 从 PSCResource 通过图片名称获取UIImage
/// - Parameter name: 图片名称
+ (UIImage *)pscImageNamed:(NSString *)name;

@end

@implementation UIImage (PSCResource)

+ (UIImage *)pscImageNamed:(NSString *)name{
    NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(kCurResPodName)];
    NSURL *url = [bundle URLForResource:kCurResBunldeName withExtension:@"bundle"];
    if (url) {
        NSBundle *imageBundle = [NSBundle bundleWithURL:url];
        UIImage *img = [UIImage imageNamed:name inBundle:imageBundle compatibleWithTraitCollection:nil];
        if (img) {
            return img;
        }
    }
    //这里兜个底,兼容资源还在主工程的时候,使用mainBundle
    return [UIImage imageNamed:name];
}

@end
  • NSBunlde:
@interface NSBundle (PSCResource)
/// 私有库获取资源
/// - Parameters:
///   - name: 资源名
///   - ext: 资源类别
+ (NSString *)pscPathForResource:(NSString *)name ofType:(NSString *)ext;
@end

@implementation NSBundle (PSCResource)
+ (NSString *)pscPathForResource:(NSString *)name ofType:(NSString *)ext {
    
    NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(kCurResPodName)];
    NSURL *url = [bundle URLForResource:kCurResBunldeName withExtension:@"bundle"];
    if (url) {
        NSBundle *resBundle = [NSBundle bundleWithURL:url];
        NSString *path = [resBundle pathForResource:name ofType:ext];
        if (path) {
            return path;
        }
    }
    //这里兜个底,兼容资源还在主工程的时候,使用mainBundle
    return [[NSBundle mainBundle] pathForResource:name ofType:ext];
}
@end

3.4 主工程读取替换

检索主工程里所有的方法:

1
2
[UIImage imageNamed:@"pic"];
[[NSBundle mainBundle] pathForResource:@"name" ofType:@"ext"];

替换成:

[UIImage pscImageNamed:@"xx"]
NSString *hotPath = [NSBundle pscPathForResource:@"yy" ofType:@"zz"];

最后检验下上述调用是否正常?