阅读 249

iOS组件化-Pod库制作的常见问题

在前面的文章中iOS组件化-私有库制作中,我们介绍了如何使用Cocoapods来制作私有库,接下来,我们主要来记录下在制作Pod库的时候碰到的一些问题。

use_frameworks!

pod库类型

swift工程中,在Xcode 9之前,swift是不支持静态库的。原因是因为那时swift还不稳定,整个swift运行时都嵌在应用程序中,它处于独立的变化中,这种情况下,使得与静态库的链接在技术上非常困难,但是动态链接是可以的,所以,我们需要在Podfile中使用 use_frameworks!,默认将pod库以动态库的形式解析。关于Podfile文件的读取可以查看这篇文章

framework有动态库和静态库两种类型,可以通过参数来指定:

use_frameworks!(:linkage => :static)  // 以静态库的形式

use_frameworks!(:linkage => :dynamic) // 以动态库的形式
复制代码

动态库与静态库混合使用

Podfile中,使用 use_framework,是全局设定,可以通过Cocoapodshook函数pre_install 来指定某一特定的库使用静态库

// Podfile

platform :ios, '13.0'
use_frameworks!

target 'HQPDemo' do
  pod 'Alamofire','~> 5.4.3'
  pod 'SnapKit'

  target 'HQPDemoTests' do
    inherit! :search_paths
  end

  target 'HQPDemoUITests' do
  end

end

$static_framework = [‘SnapKit’]

pre_install do |install|
  puts install
  install.pod_targets.each {| pod |
    if $static_framework.include?(pod.name)
      def pod.build_type;
        Pod::BuildType.static_framework # 使用静态库
      end
    end
  }
end
复制代码

通过pre_install函数,将 SnapKit指定为静态库,其他Pod库为默认类型动态库

Swift静态库

podspec中指定static_frameworktrue,可以指定为静态库。

 s.static_framework = true
复制代码

小结:

在得知源码的情况下,我们可以通过 static_framework来指定为静态库。如果不想改变已有的pod库,可以使用 pre_install函数来改变特定库的类型。

resource 和 resource_bundle

书写形式

Podspec指定资源文件有两种方式 resourceresource_bundleresourceresource_bundle都支持 xcassets

 # 1
 s.resource = 'HQPVinRecognized/Assets/*.{xcassets,bundle,lic}
 
 # 2
 s.resource_bundles = {
        'HQPFinancing' => ['HQPFinancing/Assets/**/*.xib', 'HQPFinancing/Assets/**/*.xcassets']
  }
复制代码
  • 1,使用 resource:指定资源文件为Assets目录下的以xcassets,bundle,lic结尾的文件。

  • 2,使用 resource_bundles:指定资源文件为Assets目录下的xib和xcassets

获取bundle

这两种方式,获取bundle的方式也不同

使用 resource:

  NSBundle *bundle = [NSBundle bundleForClass:[self class]]
复制代码

使用 resource_bundles:

func myBundle() -> Bundle? {
    let path = Bundle(for: xxxxxxVC.self).resourcePath?.appending("/HQPFinancing.bundle")

    guard let path = path else {
        return nil
    }
    let bundle = Bundle(path: path)
    
    return Bundle
}
复制代码

使用 resoure_bundles时,加载bundle文件会有一些硬编码cocoapods官方推荐使用resoure_bundles,因为,当 pod库为静态库时,资源文件都会加载到主bundle中,使用resource, 如果不同库文件存在同名的文件,会造成文件冲突

加载图片资源

 UIImage * normal = [UIImage imageNamed:@"icon-light-1" inBundle:bundle compatibleWithTraitCollection:nil]
复制代码

这两种方式都支持xcasset资源加载,使用 imageNamed:inBundle:compatibleWithTraitCollection方法,可以在指定的bundle中,从xcasset中,加载图片资源。

私有库依赖私有库

在制作 HQPFinancing组件的时候,需要依赖私有库MBProgressHUDExtension

// HQPFinancing.podspec

s.dependency 'MBProgressHUDExtension'
复制代码

直接添加 dependency 依赖即可。 在测试工程的Podfile,添加远程私有仓库源

// Podfile
source "https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git"
source "http://gitlab.xxxx.com/ios-xxx/xxxxx/xxxPrivateSpecs.git"

use_frameworks!
platform :ios, '9.0'

target 'HQPFinancing_Example' do
  pod 'HQPFinancing', :path => '../'
  target 'HQPFinancing_Tests' do
    inherit! :search_paths
    
  end
end
复制代码

在验证podspec合理性时,需要指定source

pod lib lint  --allow-warnings --sources=https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git,http://gitlab.xxxx.com/ios-xxx/xxxxx/xxxPrivateSpecs.git
复制代码

本地调试依赖的私有库

私有库依赖私有库的基础上,指定本地私有库的path路径

// Podfile
source "https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git"
source "http://gitlab.xxxx.com/ios-xxx/xxxxx/xxxPrivateSpecs.git"

use_frameworks!
platform :ios, '9.0'

target 'HQPFinancing_Example' do
  pod 'HQPFinancing', :path => '../'
  pod 'MBProgressHUDExtension',:path => '../../MBProgressHUDExtension'
  target 'HQPFinancing_Tests' do
    inherit! :search_paths
    
  end
end
复制代码

包含 .a 文件

  s.vendored_libraries = 'xxxxx/Classes/**/xxxxxx.a'
复制代码

包含 .framework 文件

  s.vendored_frameworks = 'xxxx/Classes/xxxx.framework'
复制代码

依赖系统 lib或framework

  s.libraries = 'sqlite3','z','c++'
  s.frameworks = 'Security','CFNetwork','CoreTelephony','SystemConfiguration','QuartzCore','CoreMotion'
复制代码

设置Other linker flag

s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-ObjC' }
复制代码

使用私有库的最新版本

pod update  --sources=http://gitlab.xxx.com/ios-xxx/xxxxxx/xxxPrivateSpecs.git
复制代码

常见问题

1,error: could not find module 'xxxxx' for target 'arm64-apple-ios-simulator'; found: i386, x86_64-apple-ios-simulator, x86_64, i386-apple-ios-simulator

pod库里面包含了一个 .a 文件,由于该.a版本比较老,在 Mac OS big Sur系统中,模拟器里面有arm64架构,该.a文件不支持模拟器的arm64架构

  s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
  s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64'}
复制代码

2,Undefined symbols for architecture i386:       "std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::compare(unsigned long, unsigned long, wchar_t const*, unsigned long) const", referenced from:VIN_TYPER::CMSegmentByDynamic::CheckSpecialVin(wchar_t*) in libvinTyper.a(MSegmentByDynamic.o)       "std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::find(wchar_t, unsigned long) const", referenced from:   VIN_TYPER::CMAuthorization::CheckSDKVersion(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >, char*) in libvinTyper.a(MAuthorization.o)

猛的一看,第一感觉是没找到符号,因为这个库是由c++写的,需要有c++环境,需要加载c++

s.libraries = 'c++'
复制代码
文章分类
iOS