swift项目集成为SDK pods下载

13 阅读4分钟

一.建立SDK打包项目

##1.创建SMSDK文件夹 ##2.打开xcode创建xcworkspace放入到SMSDK文件夹 截屏2026-02-09 17.42.01.png
##3.新建framework归于SMSDK.xcworkspace 截屏2026-02-09 17.45.36.png 截屏2026-02-09 17.46.39.png ##3.SMSDK的pod init pod install(因为up主的要打SDK包的项目pod集成了第三方库) 截屏2026-02-09 17.50.58.png 这里就随便举几个例子 截屏2026-02-09 17.52.25.png ##4.配置SDK 1.设置SDK最低支持版本和对应支持设备 截屏2026-02-09 17.55.46.png 2.设置SDK为静态库 截屏2026-02-09 17.56.49.png 3.linker flags添加-objc 截屏2026-02-09 17.57.56.png 4.prelink为yes 截屏2026-02-09 17.58.49.png 5.新建对外暴露的文件,类,方法,属性等等

import UIKit
open class LDIMSDK: NSObject {
    
    public static func getBundleImage(target: UIViewController) {
        let img = UIImage.bundledImage(named: "icon-20")
        let img1 = UIImage.bundledImage(named: "icon-20.png")
        let img2 = UIImage.bundledImage(named: "icon-30")
        let img3 = UIImage.bundledImage(named: "icon-30.png")
        let img4 = UIImage.bundledImage(named: "icon-40")
        let img5 = UIImage.bundledImage(named: "icon-40.png")
        print(img)
        print(img1)
        print(img2)
        print(img3)
        print(img4)
        print(img5)
        if let image = UIImage.bundledImage(fileName: "icon-40.png"){
            print("✅ \(image) 加载成功: \(image.size)")
        } else {
            print("❌ 加载失败")
        }
        if let image = UIImage.bundledImage(fileName: "icon-20.png"){
            print("✅ \(image) 加载成功: \(image.size)")
        } else {
            print("❌ 加载失败")
        }
        let imageview1 = UIImageView(image: img)
        imageview1.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
        let imageview2 = UIImageView(image: img2)
        imageview2.frame = CGRect(x: 100, y: 200, width: 100, height: 100)
        
        let imageview3 = UIImageView(image: img4)
        imageview1.frame = CGRect(x: 100, y: 300, width: 100, height: 100)
        
        target.view.addSubview(imageview1)
        target.view.addSubview(imageview2)
        target.view.addSubview(imageview3)
    }
}
import UIKit

extension UIImage {
    
    /// 从 SDK Bundle 中加载图片
    /// - Parameter imageName: 图片名称(不含扩展名)
    /// - Returns: UIImage 对象,如果找不到则返回空图片
    static func bundledImage(named imageName: String) -> UIImage? {
        #if DEBUG
        print("🔍 LDIMSDK: 尝试加载图片 '\(imageName)'")
        #endif
        
        // 获取 SDK 的 Bundle
        guard let bundle = Bundle.sdkBundle else {
            print("⚠️ LDIMSDK: 无法找到 SDK Bundle")
            return nil
        }
        
        #if DEBUG
        print("  SDK Bundle 路径: \(bundle.bundlePath)")
        #endif
        
        // 方式1: 从 Assets.xcassets (编译后的 Assets.car) 中加载
        // 这是最优先的方式,因为 XCFramework 中的图片通常会被编译到 Assets.car
        if let image = UIImage(named: imageName, in: bundle, compatibleWith: nil) {
            #if DEBUG
            print("  ✅ 从 Assets.car 加载成功: \(image.size)")
            #endif
            return image
        }
        
        // 方式2: 从嵌套的 .bundle 中加载
        if let resourceBundle = Bundle.resourceBundle {
            #if DEBUG
            print("  尝试从 Resource Bundle: \(resourceBundle.bundlePath)")
            #endif
            if let image = UIImage(named: imageName, in: resourceBundle, compatibleWith: nil) {
                #if DEBUG
                print("  ✅ 从 Resource Bundle 加载成功: \(image.size)")
                #endif
                return image
            }
        }
        
        // 方式3: 尝试直接从文件路径加载 (从 SDK Bundle)
        let imageExtensions = ["png", "jpg", "jpeg", "pdf"]
        for ext in imageExtensions {
            if let path = bundle.path(forResource: imageName, ofType: ext) {
                #if DEBUG
                print("  找到文件路径: \(path)")
                #endif
                if let image = UIImage(contentsOfFile: path) {
                    #if DEBUG
                    print("  ✅ 从文件路径加载成功: \(image.size)")
                    #endif
                    return image
                }
            }
            
            // 同时尝试从资源 bundle 中加载
            if let resourceBundle = Bundle.resourceBundle,
               let path = resourceBundle.path(forResource: imageName, ofType: ext) {
                #if DEBUG
                print("  找到 Resource Bundle 文件路径: \(path)")
                #endif
                if let image = UIImage(contentsOfFile: path) {
                    #if DEBUG
                    print("  ✅ 从 Resource Bundle 文件路径加载成功: \(image.size)")
                    #endif
                    return image
                }
            }
        }
        print("❌ LDIMSDK: 无法找到图片 '\(imageName)'")
        #if DEBUG
        // 列出 Bundle 中的所有文件以便调试
        if let contents = try? FileManager.default.contentsOfDirectory(atPath: bundle.bundlePath) {
            print("  Bundle 中的文件:")
            contents.prefix(10).forEach { print("    - \($0)") }
        }
        #endif
        return nil
    }
    
    /// 从 SDK Bundle 中加载图片(使用完整文件名)
    /// - Parameter fileName: 图片文件名(含扩展名)
    /// - Returns: UIImage 对象
    static func bundledImage(fileName: String) -> UIImage? {
        guard let bundle = Bundle.sdkBundle else {
            print("⚠️ LDIMSDK: 无法找到 SDK Bundle")
            return nil
        }
        
        let components = fileName.components(separatedBy: ".")
        let name = components.first ?? fileName
        let ext = components.count > 1 ? components.last : nil
        
        if let path = bundle.path(forResource: name, ofType: ext) {
            return UIImage(contentsOfFile: path)
        }
        
        if let resourceBundle = Bundle.resourceBundle,
           let path = resourceBundle.path(forResource: name, ofType: ext) {
            return UIImage(contentsOfFile: path)
        }
        
        return nil
    }
}

// MARK: - Bundle Extension
extension Bundle {
    
    /// SDK 的主 Bundle
    static var sdkBundle: Bundle? {
            
        // 方式1: 通过类获取 Bundle
        let bundle = Bundle(for: LDIMSDKBundleMarker.self)
        
        // 方式2: 如果是 XCFramework,可能需要这样获取
        if bundle.bundleURL.pathExtension == "framework" {
            print("方式2: 如果是 XCFramework,可能需要这样获取\(bundle)")
            return bundle
        }
        
        // 方式3: 尝试获取 LDIMSDK.framework
        if let frameworkBundle = Bundle(identifier: "LDIMSDK") {
            print("// 方式3: 尝试获取 LDIMSDK.framework\(frameworkBundle)")
            return frameworkBundle
        }
        
        return bundle
    }
    
    /// SDK 资源 Bundle (如果使用了单独的资源 bundle)
    static var resourceBundle: Bundle? {
        guard let sdkBundle = sdkBundle else { return nil }
        
        // 查找 LDIMSDK.bundle
        if let bundlePath = sdkBundle.path(forResource: "LDIMSDK", ofType: "bundle"),
           let resourceBundle = Bundle(path: bundlePath) {
            return resourceBundle
        }
        
        // 查找其他可能的资源 bundle 名称
        let bundleNames = ["LDIMSDKResources", "Resources", "mm"]
        for bundleName in bundleNames {
            if let bundlePath = sdkBundle.path(forResource: bundleName, ofType: "bundle"),
               let resourceBundle = Bundle(path: bundlePath) {
                return resourceBundle
            }
        }
        
        return nil
    }
    /// 从 SDK 所在 Bundle 加载图片,便于以 Framework 形式集成时正确找到资源;找不到时回退到 main Bundle
    static func sdk(named name: String) -> UIImage? {
        UIImage(named: name, in: LDIM.sdkBundle, compatibleWith: nil)
        ?? UIImage(named: name)
    }
}

// MARK: - Bundle Marker Class
/// 用于标识 SDK Bundle 的辅助类
private class LDIMSDKBundleMarker {
    // 这个类只用于获取 Bundle,不需要任何实现
}

public class LDIM {
    
    /// SDK 内部使用的 Bundle,不对外暴露
    static var sdkBundle: Bundle {
        Bundle(for: LDIM.self)
    }
    
}

6.建立Bundle管理资源文件 截屏2026-02-09 18.07.51.png 截屏2026-02-09 18.08.07.png 截屏2026-02-09 18.08.33.png 7.添加对外暴露文件 截屏2026-02-09 18.10.05.png 8.以下是脚本文件(真机和模拟器一起生成SDK)

#!/bin/bash

# =====================================================
# SMSDK XCFramework 构建脚本
# 用于生成同时支持模拟器和真机的通用 Framework
# =====================================================

set -e

# ==================== 配置参数 ====================
SCHEME_NAME="SMSDK"
PROJECT_NAME="SMSDK"
FRAMEWORK_NAME="SMSDK"
OUTPUT_DIR="./Build"
FRAMEWORK_PATH="${OUTPUT_DIR}/XCFramework"

# 工作区路径
WORKSPACE_PATH="./SMSDK/${PROJECT_NAME}.xcworkspace"

# 如果没有 workspace,使用 project
if [ ! -d "$WORKSPACE_PATH" ]; then
    PROJECT_PATH="./SMSDK/${PROJECT_NAME}.xcodeproj"
    BUILD_OPTION="-project ${PROJECT_PATH}"
else
    BUILD_OPTION="-workspace ${WORKSPACE_PATH}"
fi

# ==================== 清理旧文件 ====================
echo "🧹 清理旧的构建文件..."
rm -rf "${OUTPUT_DIR}"
mkdir -p "${OUTPUT_DIR}"

# ==================== 构建真机 Framework ====================
echo "📱 开始构建真机 (iOS) Framework..."
xcodebuild archive \
    ${BUILD_OPTION} \
    -scheme "${SCHEME_NAME}" \
    -configuration Release \
    -destination "generic/platform=iOS" \
    -archivePath "${OUTPUT_DIR}/iOS.xcarchive" \
    SKIP_INSTALL=NO \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    | xcpretty || true

# ==================== 构建模拟器 Framework ====================
echo "🖥️  开始构建模拟器 (iOS Simulator) Framework..."
xcodebuild archive \
    ${BUILD_OPTION} \
    -scheme "${SCHEME_NAME}" \
    -configuration Release \
    -destination "generic/platform=iOS Simulator" \
    -archivePath "${OUTPUT_DIR}/iOSSimulator.xcarchive" \
    SKIP_INSTALL=NO \
    BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
    | xcpretty || true

# ==================== 创建 XCFramework ====================
echo "📦 创建 XCFramework..."
xcodebuild -create-xcframework \
    -framework "${OUTPUT_DIR}/iOS.xcarchive/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework" \
    -framework "${OUTPUT_DIR}/iOSSimulator.xcarchive/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework" \
    -output "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}.xcframework"

# ==================== 清理中间文件 ====================
echo "🧹 清理中间文件..."
rm -rf "${OUTPUT_DIR}/iOS.xcarchive"
rm -rf "${OUTPUT_DIR}/iOSSimulator.xcarchive"

# ==================== 完成 ====================
echo "✅ 构建完成!"
echo "📦 XCFramework 位置: ${FRAMEWORK_PATH}/${FRAMEWORK_NAME}.xcframework"
echo ""
echo "使用方法:"
echo "1. 拖拽 ${FRAMEWORK_NAME}.xcframework 到你的项目中"
echo "2. 在 General -> Frameworks, Libraries, and Embedded Content 中设置为 'Embed & Sign'"

然后终端跑

cd 目标文件夹
# 1. 赋予脚本执行权限
chmod +x build_xcframework.sh
# 2. 执行构建
./build_xcframework.sh

至此SDK生成成功 截屏2026-02-09 18.22.25.png

#二.配置spec 1.配置podspec文件 1).新建文件夹SMUP 2).终端创建podspec文件

pod spec create SMSDK

截屏2026-02-10 13.56.58.png

Pod::Spec.new do |spec|


  spec.name         = "SMSDK"
  spec.version      = "0.0.1"
  spec.summary      = "简短的SDK描述"

  spec.description  = <<-DESC
  这是对SDK的一段描述
                   DESC

  spec.homepage     = "https://github.com/saman008/SMSDK"

  spec.license      = "MIT (example)"
  spec.license      = { :type => "MIT", :file => "FILE_LICENSE" }

  spec.author       = { "saman008" => "1975566197@qq.com" }

  spec.platform     = :ios, "15.0"

  spec.source       = { :git => "https://github.com/saman008/SMSDK.git", :tag => "#{spec.version}" }


  spec.vendored_frameworks  = "SMSDK.xcframework"

  spec.source_files = 'SMSDK/*.{swift,h,m}'
  spec.resource_bundles = {
    'SMSDK' => ['SMSDK.xcframework/ios-arm64/SMSDK.framework/SMSDK.bundle/**/*.{storyboard,xib,xcassets,json,imageset,png,strings,mp3}'],
    'SMSDK' => ['SMSDK.xcframework/ios-arm64_x86_64-simulator/SMSDK.framework/SMSDK.bundle/**/*.{storyboard,xib,xcassets,json,imageset,png,strings,mp3}'],
  }


  # 必须的框架
   spec.frameworks = 'UIKit', 'Foundation'
    # 静态框架
   spec.static_framework = true
   spec.ios.deployment_target = '15.0'
   spec.swift_version = ['5.0']
  #以下是你引用的第三方库 最好把三方库对应的版本加上
   spec.dependency "RxCocoa", "~> 6.6.0"
   spec.dependency "SnapKit"
   spec.dependency "RxSwift"
   spec.dependency "RxDataSources"
   spec.dependency "RxGesture"
   spec.dependency "Differentiator"
   spec.dependency "RxRelay"

end

2.远程仓库 截屏2026-02-10 14.11.15.png 3.clone项目到SMUP文件夹中 截屏2026-02-10 14.14.22.png

在pod里面添加这些

pod 'SMSDK', :path => 'Pods/SMUP'

post_install do |installer|
 installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
          config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = "YES"#yes一定要加
    end
  end
end

然后pod install 截屏2026-02-10 14.23.18.png 最后展示结果(bundle里面的图片加载成功,调用对应类方法成功) 截屏2026-02-10 14.28.27.png SDK本地拖入成功 #三.建立分发出去的git的SDK包 下面介绍git远程依赖 截屏2026-02-10 14.30.43.png 注意打tag 要和spec上的保持一致 我只里都是0.0.1

spec.version      = "0.0.1"

pod上添加对应远程路径

 pod 'SMSDK', :git => 'https://github.com/saman008/SMSDK.git', :tag => '0.0.1'

然后pod install一下

截屏2026-02-10 14.33.07.png 最后项目跑一下 也是成功 截屏2026-02-10 14.35.09.png

完美 撒花🎉 觉得有用的大佬给个点赞和打赏,只对我最好的支持

最后有些同学想要pod xxx这样的引用第三方库 如下 仓库推送到CocoaPods上

pod trunk register 邮箱 ‘用户名’

注意:邮箱为github上的登录邮箱、用户名为github上的用户名 注册后,你填写的邮箱会收到一份确认邮件,点击里面的链接,注册成功。

pod trunk me

推送到CocoaPods 把你的.podspec文件推送到CocoaPods上

pod trunk push SMIMDEMOSDK.podspec --allow-warnings

成功了 截屏2026-02-10 15.15.32.png 查询对应的第三方库

pod search SMIMDEMOSDK

我这里刚注册成功 估计没那么快显示,而且本来应该SMSDK的名字的但是被别人占了,就改了 截屏2026-02-10 15.17.37.png