Framework 之 Bundle

新建 Bundle

  • macOS -> Framework & Library -> Bundle

配置 Bundle

  • Build Settings -> Base SDK -> iOS

  • Build Settings -> Enable Bitcode -> NO

  • Build Settings -> COMBINE_HIDPI_IMAGES -> NO

    防止 Bundle 中的图片变成 tiff 格式

  • Build Settings -> Skip Install -> YES

  • Build Settings -> 删除安装路径 Installation Directory 的值

Framework 编译 Bundle

  • TARGETS -> Framework -> Build Phases -> Dependencies -> 添加 Bundle
    -> TARGETS -> Bundle -> 添加 Run Script -> ${SRCROOT}/build_bundle.sh
#!/bin/sh

#cp -r ${SRCROOT}/Mixed/Mixed.xcassets ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.bundle

BUNDLE_DIR=${TARGET_BUILD_DIR}/${PRODUCT_NAME}.bundle

echo "================================"
echo "拷贝 ${BUNDLE_DIR} "
echo "================================"

# 拷贝到 Frameworks 目录
DST_DIR="../Frameworks"
if [ ! -d ${DST_DIR} ]; then
mkdir -p "${DST_DIR}"
fi

rm -rf ${DST_DIR}/${PRODUCT_NAME}.bundle
cp -af ${BUNDLE_DIR} ${DST_DIR}

rm -rf ${DST_DIR}/Mixed.xcassets
cp -af ${SRCROOT}/Mixed/Mixed.xcassets ${DST_DIR}

Example Code

import Foundation
import UIKit

/**
 * 在 PROJECT -> TARGETS -> Build Phases -> Link Binary With Libraries 中加入 Mixed.framework
 * 在 PROJECT -> TARGETS -> Build Phases -> Copy Bundle Resources   中加入 MixedSources.bundle
 */
class MixedBundle { }

extension Bundle {
    
    static func mixed_bundle() -> Bundle {
       let bundle = Bundle(for: MixedBundle.self)
       return bundle
    }
   
   static func mixed_sourceBundle() -> Bundle {
       let live_bundle = mixed_bundle()
       let bundlePath = live_bundle.path(forResource: Bundle.mixed_resources, ofType: nil)
       let bundle = Bundle(path: bundlePath ?? live_bundle.bundlePath)
       return bundle!
   }
    
    static let mixed_resources = "MixedSources.bundle"
    
    @objc public static func mixed_filePath(_ fileName: String) -> String? {
        let bundle = mixed_bundle()
        let path = bundle.path(forResource: "\(Bundle.mixed_resources)/\(fileName)", ofType: nil)
        guard path != nil else {
            return bundle.path(forResource: fileName, ofType: nil)
        }
        return path
    }
}

// 图片
extension UIImage {
    @objc(mixed_imageNamed:)
    public static func mixed_image(named name: String) -> UIImage? {
        var image: UIImage? = UIImage(named: name, in: Bundle.mixed_sourceBundle(), compatibleWith: nil)
        if image == nil {
            image = UIImage(named: name, in: Bundle.mixed_bundle(), compatibleWith: nil)
        }
        
        return image
    }
}

// 自定义字体
extension UIFont {
    @objc(mixed_58SmileFontBold:)
    public class func mixed_58SmileFontBold(size fontSize: CGFloat) -> UIFont? {
        UIFont.mixed_registerFonts
        return UIFont(name: "58SmileFont-Bold", size: fontSize)
    }
    
    @objc(mixed_don58Regular:)
    public class func mixed_don58Regular(size fontSize: CGFloat) -> UIFont? {
        UIFont.mixed_registerFonts
        return UIFont(name: "don58-Regular", size: fontSize)
    }
    
    @objc(mixed_don58Medium:)
    public class func mixed_don58Medium(size fontSize: CGFloat) -> UIFont? {
        UIFont.mixed_registerFonts
        return UIFont(name: "don58-Medium", size: fontSize)
    }
}

enum WBVRegisterFontError: Error {
    case invalidFontFile
    case fontPathNotFound
    case initFontError
    case registerFailed
}

extension UIFont {
    // 注册字体只需执行一次
    public static let mixed_registerFonts: () = {
        let bundle = Bundle.mixed_sourceBundle()
        
        try? mixed_registerFont(in:bundle, name: "don-Regular", type: "ttf")
        try? mixed_registerFont(in:bundle, name: "don-Medium", type: "ttf")
        
        print("===========================")
        UIFont.familyNames.forEach { (font) in
            print("Family Name: \(font)")
            UIFont.fontNames(forFamilyName: font).forEach({
                print("  Font Name: \($0)")
            })
        }
    }()
    
    // 注册字体
    @objc(mixed_registerFont:filename:type:error:)
    public static func mixed_registerFont(in bundle: Bundle?, name fileName: String, type: String?) throws {
        guard let resourceBundleURL = bundle?.path(forResource: fileName, ofType: type) else {
            throw WBVRegisterFontError.fontPathNotFound
        }
        
        guard let fontData = NSData(contentsOfFile: resourceBundleURL), let dataProvider = CGDataProvider.init(data: fontData) else {
            throw WBVRegisterFontError.invalidFontFile
        }
        
        guard let fontRef = CGFont.init(dataProvider) else {
            throw WBVRegisterFontError.initFontError
        }
        
        var errorRef: Unmanaged<CFError>? = nil
        guard CTFontManagerRegisterGraphicsFont(fontRef, &errorRef) else {
            throw WBVRegisterFontError.registerFailed
        }
    }
}

推荐阅读更多精彩内容