学习组件化资源文件管理方案后的总结

起因

组件化之前,所有代码、资源文件都在主工程中,其中大量图片资源,不可避免就会出现命名冲突问题。一般情况下,我们需要一份严谨的命名规范,比如根据模块进行划分添加前缀,来避免命名冲突。

公司采用组件化方案,但是未对资源文件进行拆分,都放在主工程中,维护组件和项目非常痛苦。apple tv我们将主工程资源文件拆分到对应的Poxcode怎么编写c语言d,交由工龄差一年工资差多少组件自己管理。这样将资源文件拆分到各个Pod,使apple watch职责划分更加合理,减少外部依赖,方便xcode是什么意思独立运行。

CocoaPods提供的功能优先级是什么意思

CocoaPodsappearance提供的有use_frameworksstatic_frameworkresourceresource_bundles 这些功能的选择,以及将其中一些功能组合使用之后资源文件的最终存储路xcode怎么编写c语言径的不同,导致使用者对图片文件、字体文件、本地化文件、其他各种文件的优先级队列种种处理方式不明所以。

组合场景下的资源文件存储路径

use_frameworks!static_frameworkresource_bundlesresources 的不同组合使用,会导致资源文件的最终存放路径不同,龚俊以下是各种场景下的路径总结:

# use_frameworks! 动态库
# static_framework 静态库 podspec文件中不声明,默认为false
# resource_budles 生成独立的bundle
# resources 不生成独立的bundle,放置在.app根目录
# ---------------------------------------------------------------------------
use_frameworks! 
	static_framework = false
		resource_bundles: .app/Frameworks/pod_name.framework/pod_name.bundle/.
		resources: .app/Frameworks/pod_name.framework/.
	static_framework = true
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.
# use_frameworks!
	static_framework = false
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.
	static_framework = true
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.

(.app/. 代表的app id注册是 main bundle)

不同路径下的图片取值方式及差别可以参考这篇文章:CocoaPods的资源管理和Asset Catalog优化 需要注意的是,当 Pod 中的 .x公积金cassets 类型资源文件最终存储在 main bundle 的话会和主工程的 .xcxcode修改项目名assets 文件冲突,编译会报优先级c语言错:

error: Multiple commands produce ‘/Users/gonghonglou/Library/Developer/Xcode/DerivedData/HoloResource-giqfnwiluvssbzbyvuhpkrjoewvd/Build/Products/Debug-iphonesimulator/HoloResource_Example.app/Assets.car’: 1) Target ‘HoloResource_Example’ (project ‘HoloResource’) has compile command with input ‘/Users/gonghonglouapple tv/holxcode怎么设置成中文o/HoloResource/Example/HoloResource/Images.xcassets’ 2) That command depends on command ingoogle Target ‘HoloResource_Example’ (project ‘HoloResapproveoappstoreurce’): script phase “[CP] Copy Pods Resources”

解决方法,在 Podfile 里添加:

install! 'cocoapods', :disable_input_output_paths => true

Tip: resource+不使用use_fram优先级别eworks! +assets时会编译失败,因为工程只会生成一份Assets.car文件

Sxcode怎么运行程序howing All Messages

2022-03-26 20:42:51.046 ibtoold[25007:9169669] Lxcode怎么设置成中文aunching AssetCatalogSimulatorAgent using native architecture.

/* com.apple.actool.errors */

:宫颈癌疫苗 error: There are multiple stickers icon set or ap优先级是什么意思p icon set instances named “AppIcon”.

题外话:Xcode 10 之后引入了新的编译系统,导致xcode修改项目名 Pod 里有代码改动的话apple id密码重置无法及时编译进工程,解决方案也是上述方法。

参考:Build System Release Notes for Xcode 10

资源处理实践

图片 UIImage

public extension Resource where Base: UIImage {
    /// 加载图片资源
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: s.resource_bundles中设置的名字 一般为组件名
    /// - Returns: description
    static func loadImage(name: String, bundleName: String) -> UIImage? {
        /// 静态库+独立bundle
        var image = loadImage1(name: name, in: bundleName)
        if image == nil {
            /// 动态库+独立bundle
            image = loadImage2(name: name, in: bundleName)
        }
        if image == nil {
            /// 动态库+非独立bundle
            image = loadImage3(name: name, in: bundleName)
        }
        if image == nil {
            // 根目录 .app/
            image = loadImage4(name: name, in: bundleName)
        }
        return image
    }
    /// 加载  .app/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage1(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/(bundleName).bundle"
        return commonLoadImage(name: name, in: pathComponent)
    }
    /// 加载  .app/Frameworks/pod_name.framework/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage2(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/Frameworks/(bundleName).framework/(bundleName).bundle"
        return commonLoadImage(name: name, in: pathComponent)
    }
    /// 加载.app/Frameworks/pod_name.framework/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage3(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/Frameworks/(bundleName).framework"
        return commonLoadImage(name: name, in: pathComponent)
    }
    /// 加载.app/
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage4(name: String, in bundleName: String) -> UIImage? {
        return UIImage(named: name)
    }
    fileprivate static func commonLoadImage(name: String, in pathComponent: String) -> UIImage? {
        guard let resourcePath: String = Bundle.main.resourcePath else { return nil }
        let bundlePath = resourcePath + pathComponent
        let bundle = Bundle(path: bundlePath)
        return UIImage(named: name, in: bundle, compatibleWith: nil)
    }
}

每个组件调用 UIImage.resource.loadImage(name: "图片名", bundxcode汽车报价leName: "组件名") 就可以访问自己 bundle 里的图片了。

这里提到的四个路径做了优先级处理:

  1. 首先访问的是静态库 + resource_bundles 的路径
  2. 其次访问的是使用 use_framewxcode修改项目名orks! + rappreciateesource_bundleappreciates 的动态库路径
  3. 再次访问的是使用 use_fr优先级调度算法ameworks! +xcode汽车报价 rexcode怎么用sources 的动态库路径
  4. 最后appointment是 main bundle 路径

最推荐也是最合理的配置方式当然是第一种,提供静态库,使用 resource_bundles 存储资源文件。

路径 Bundle

既然图片可以通过这种方式封装,那么参照这种思路将 bundle 封装一个基础方法,有了统一的 bundle 调用方法,其他资源文件的访问就简单的多了。

public extension Resource where Base: Bundle {
    /// 加载图片资源
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: s.resource_bundles中设置的名字 一般为组件名
    /// - Returns: description
    static func loadBundle(in bundleName: String) -> Bundle? {
        var image = loadBundle1(in: bundleName)
        if image == nil {
            image = loadBundle2(in: bundleName)
        }
        if image == nil {
            image = loadBundle3(in: bundleName)
        }
        if image == nil {
            image = loadBundle4(in: bundleName)
        }
        return image
    }
    /// 加载  .app/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle1(in bundleName: String) -> Bundle? {
        let pathComponent = "/(bundleName).bundle"
        return commonLoadBundle(in: pathComponent)
    }
    /// 加载  .app/Frameworks/pod_name.framework/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle2(in bundleName: String) -> Bundle? {
        let pathComponent = "/Frameworks/(bundleName).framework/(bundleName).bundle"
        return commonLoadBundle(in: pathComponent)
    }
    /// 加载.app/Frameworks/pod_name.framework/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle3(in bundleName: String) -> Bundle? {
        let pathComponent = "/Frameworks/(bundleName).framework"
        return commonLoadBundle(in: pathComponent)
    }
    /// 加载.app/
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle4(in bundleName: String) -> Bundle? {
        return Bundle.main
    }
    fileprivate static func commonLoadBundle(in pathComponent: String) -> Bundle? {
        guard let resourcePath = Bundle.main.resourcePath else { return nil }
        let bundlePath = resourcePath + pathComponent
        let bundle = Bundle(path: bundlePath)
        return bundle
    }
}

使用

Swift组件化资源管理

// module_a图片名 ModuleA资源名,一般为组件名
let imagea = UIImage.resource.loadImage(name: "module_a", bundleName: "ModuleA")

实践Demo链接

感谢

组件化资源文件管理方案