Cocoapods制作pod時,依賴百度地圖SDK的一些問題

1、制作一個pod時,依賴了百度地圖sdk(靜態庫),這個時候,Cocoapods會在百度地圖sdk這個pod中的podspec中為項目配置百度地圖sdk需要的系統動態庫及靜態庫。編譯新做的pod,得到framework,分析它的二進制,沒有多余的代碼,但是二進制卻有6.9M,使用 otool 分析得到:

denglibing$ otool -L /Users/denglibing/Library/Developer/Xcode/DerivedData/HDPodBMKSDK-hbkvrvffwquplafimjwrnqklfktr/Build/Products/Debug-iphonesimulator/HDPodBMKSDK.framework/HDPodBMKSDK 
/Users/denglibing/Library/Developer/Xcode/DerivedData/HDPodBMKSDK-hbkvrvffwquplafimjwrnqklfktr/Build/Products/Debug-iphonesimulator/HDPodBMKSDK.framework/HDPodBMKSDK:
@rpath/HDPodBMKSDK.framework/HDPodBMKSDK (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 254.6.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.2.0)
/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1070.22.0)
/System/Library/Frameworks/CoreLocation.framework/CoreLocation (compatibility version 1.0.0, current version 2101.0.62)
/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony (compatibility version 1.0.0, current version 0.0.0)
/System/Library/Frameworks/OpenGLES.framework/OpenGLES (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/QuartzCore.framework/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
/System/Library/Frameworks/Security.framework/Security (compatibility version 1.0.0, current version 0.0.0)
/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration (compatibility version 1.0.0, current version 888.50.20)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1349.54.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.dylib (compatibility version 1.0.0, current version 1238.50.2)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1349.55.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3600.7.47)
/usr/lib/libc++abi.dylib (compatibility version 1.0.0, current version 307.2.0)

其中 libsqlite3.dylib 我找了一下發現有4.4M

而libstdc++.6.dylib則是libstdc++.6.0.9.dylib的替身,libstdc++.6.0.9.dylib是1.5M

libobjc.A.dylib有14.2M

libSystem.dylib則是libSystem.B.dylib的替身,libSystem.B.dylib大小是61KB

libc++abi.dylib有440KB

/System/Library/Frameworks/下面的一些系統的framework都很大,比如/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics就有23.8M

顯然,這些 /usr/lib/ 和 /System/Library/Frameworks/ 下面的庫肯定不是在我剛剛制作的二進制中,它們應該只是依賴關系,用到的時候通過地址去找。

那么這6.9M的體積是怎么來的呢? 下面回給出答案。

2、在主工程使用剛剛制作好的framework:

制作的pod的podspec

# HDPodBMKSDK.podspec 
Pod::Spec.new do |s|
    s.name         = "HDPodBMKSDK"
    s.module_name  = "HDPodBMKSDK"
    s.version      = "0.0.1"
    s.summary      = "HDPodBMKSDK"
    s.description  = "這個是用到百度地圖sdk的一個pod工程"
    s.homepage     = "https://github.com/erduoniba"
    s.author       = { "denglibing" => "13049862397@163.com" }
    s.platform     = :ios, "8.0"
    s.requires_arc = true
    s.license      = { :type => 'MIT'}
    s.source       =  { :git => 'https://github.com/erduoniba/HDPodBMKSDK.git', :tag => "#{s.version}"}

    s.subspec 'HDPodBMKSDK' do |hdBMK|
        hdBMK.source_files = 'HDPodBMKSDK/*.{h,m,mm}'
    end

    s.dependency 'BaiduMapKit'

    #-undefined dynamic_lookup 這個表明了當主工程和framework都包含同一個庫時,會優先使用主工程的庫。
    s.pod_target_xcconfig = {
        'FRAMEWORK_SEARCH_PATHS'   => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit',
        'LIBRARY_SEARCH_PATHS'     => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit/thirdlibs',
        'OTHER_LDFLAGS'            => '$(inherited) -undefined dynamic_lookup -ObjC',
        'ENABLE_BITCODE'           => 'NO'
    }
end

主工程的Podfile:

platform :ios,'8.0'

#cocoapods使用framework模式,意思就是.a的靜態庫不支持使用cocoapods管理,在包含swift的項目中,需要使用這樣的模式,因為swift不支持靜態庫,(原因:靜態庫在編譯的時候就打包加入到項目的二進制中,但是目前的iPhone設備中還沒有支持對swift的解析,所以不能載靜態庫中編寫swift代碼,動態庫則可以,因為項目使用swift后會在項目中添加swift解析的動態庫到工程中,也就是如此所以使用swift的項目打包出來的ipa體積會變大,如下圖,當引用的swift需要的依賴庫越多,占用的體積越大)
use_frameworks!
inhibit_all_warnings!

target 
'HDPodBMKDemo' do
pod 'HDPodBMKSDK', :path => ‘../HDPodBMKSDK’
end

#百度地圖SDK現在使用的7個framework,為了支持ssl所以還添加了兩個.a的靜態庫,這個時候需要使用如下命令來讓cocoapods對靜態庫支持

# pod1.3.0之前需要這樣
pre_install do |installer|
# workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
def installer.verify_no_static_framework_transitive_dependencies; end
end

# pod1.3.0之后需要這樣
pre_install do |installer|
    # workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
    Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
end

使用swift的項目打包出來的ipa體積會變大:

編譯主工程得到ipa包,打開后:

denglibing$ tree -L 3
├── Base.lproj
│   ├── LaunchScreen.storyboardc
│   │   ├── 01J-lp-oVM-view-Ze5-6b-2t3.nib
│   │   ├── Info.plist
│   │   └── UIViewController-01J-lp-oVM.nib
│   └── Main.storyboardc
│       ├── BYZ-38-t0r-view-8bC-Xf-vdC.nib
│       ├── Info.plist
│       └── UIViewController-BYZ-38-t0r.nib
├── Frameworks
│   └── HDPodBMKSDK.framework
│       ├── HDPodBMKSDK
│       ├── Info.plist
│       └── _CodeSignature
├── HDPodBMKDemo
├── Info.plist
├── PkgInfo
├── _CodeSignature
│   └── CodeResources
└── mapapi.bundle
    ├── files
    │   └── cfg
    └── images
        ├── baidumap_logo.png

果然發現了剛剛我們所做的framework,查看大小,驚人的發現它只有了53KB

繼續使用otool分析:

denglibing$ otool -L HDPodBMKSDK 
HDPodBMKSDK:
@rpath/HDPodBMKSDK.framework/HDPodBMKSDK (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1349.54.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.dylib (compatibility version 1.0.0, current version 1238.50.2)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1349.55.0)
/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1070.22.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3600.7.47)

和上面的對比,現在少了這些:

/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.2.0)
/System/Library/Frameworks/CoreLocation.framework/CoreLocation (compatibility version 1.0.0, current version 2101.0.62)
/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony (compatibility version 1.0.0, current version 0.0.0)
/System/Library/Frameworks/OpenGLES.framework/OpenGLES (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/QuartzCore.framework/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
/System/Library/Frameworks/Security.framework/Security (compatibility version 1.0.0, current version 0.0.0)
/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration (compatibility version 1.0.0, current version 888.50.20)
/usr/lib/libc++abi.dylib (compatibility version 1.0.0, current version 307.2.0)

查看百度地圖官網的集成:

http://lbsyun.baidu.com/index.php?title=iossdk/guide/buildproject
第二步、引入所需的系統庫
百度地圖SDK中提供了定位功能和動畫效果,v2.0.0版本開始使用OpenGL渲染,因此您需要在您的Xcode工程中引入CoreLocation.framework和QuartzCore.framework、OpenGLES.framework、SystemConfiguration.framework、CoreGraphics.framework、Security.framework、libsqlite3.0.tbd(xcode7以前為 libsqlite3.0.dylib)、CoreTelephony.framework 、libstdc++.6.0.9.tbd(xcode7以前為libstdc++.6.0.9.dylib)。

(注:紅色標識的系統庫為v2.9.0新增的系統庫,使用v2.9.0及以上版本的地圖SDK,務必增加導入這3個系統庫。)

添加方式: 在Xcode的Project -> Active Target ->Build Phases ->Link Binary With Libraries,添加這幾個系統庫即可。

由此可見,動態庫獨立出去的時候,包含了動態庫能獨立在運行時所需要的環境,但是沒有想到這些需要環境的說明竟然占居了這么大的體積,雖然最后在加入到項目中后會把這部分體積清空掉,這也讓我想到,不要一味的看第三方framework的體積了,畢竟它需要依賴的系統動態庫也需要很多體積進行說明。

而現在,注意觀察ipa,一共是13M,其中主項目的二進制占了6.9M,百度地圖的資源占用了6M,說明百度需要系統庫從剛剛我們自己做的framework轉移給了 主項目的二進制,但是最終這 6.9M的體積何去何從在我這里還是一個謎

otool分析這個二進制,發現和打包出來的framework一致。

和同事討論,他的意思這多出來的6.9M肯定是百度地圖SDK產生的,而不是上面所說的對依賴的系統動態庫說明產生的。這個可能是Cocoapods做了很多處理:

單獨打包framework的時候,因為百度地圖sdk有.a靜態庫,所以Cocoapods默認將其全部做成了靜態庫,加入到自己做的framework中,當主工程也使用這個百度的時候,Cocoapods給我們的sdk做了一次引用,但是同樣將它們做成靜態庫加入到 項目的二進制中,也就是說這6.9M是這樣轉移了的。

但是這個需要證實。

這里有一個大問題:百度地圖相關的代碼嵌入到了主工程的二進制中,在自己制作的framework中是沒有相關百度地圖代碼的,這樣明顯跑不起來的。

這里會遇到一下問題:

問題: 為什么使用pod,debug可以跑起來,而release卻失敗?

# http://www.tuicool.com/articles/Ybq6Rf3
release打包出來安裝,一點擊運行,變crash了,View Device Logs:

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY

Termination Description: DYLD, Symbol not found: OBJC_CLASS$_BMKMapView | Referenced from: /private/var/containers/Bundle/Application/50F3B444-F54E-4AF1-8C13-D60FBEC0F669/HDPodBMKDemo.app/Frameworks/HDPodBMKSDK.framework/HDPodBMKSDK | Expected in: flat namespace | in /private/var/containers/Bundle/Application/50F3B444-F54E-4AF1-8C13-D60FBEC0F669/HDPodBMKDemo.app/Frameworks/HDPodBMKSDK.framework/HDPodBMKSDK

Triggered by Thread:  0

原因解答:因為 Debug 版本暴露了所有自定義類的符號以便于調試,因此你的 framework 可以找到相應的符號,而 Release 版本則不會。

3、既然這樣,怎么處理呢?

3.1、主工程和framework同時包含百度地圖好了。

像這樣子,就可以了,但是值得注意的地方是,兩邊都有百度地圖,需要在兩邊進入地圖實現百度的一些代碼,也就是下面的代碼需要寫兩份:

    BMKMapManager* _mapManager = [[BMKMapManager alloc]init];
    // 如果要關注網絡及授權驗證事件,請設定     generalDelegate參數
    BOOL ret = [_mapManager start:@"qbfQUpMvsAkqgwFZL8YVy89dK9ZXZE3h" generalDelegate:nil];
    if (!ret) {
        NSLog(@"manager start failed!");
    }

這樣無論是debug還是release,都是正常的,缺點很明顯百度在兩邊都存在了,項目體積也大了:

同時在運行的時候Xcode的log日志:

objc[10502]: Class BMSDKKeychainItemWrapper is implemented in both /private/var/containers/Bundle/Application/B5A38F9D-E271-491C-B95D-6C05671D2332/HDPodBMKDemo.app/Frameworks/HDPodBMKSDK.framework/HDPodBMKSDK (0x100f951d8) and /var/containers/Bundle/Application/B5A38F9D-E271-491C-B95D-6C05671D2332/HDPodBMKDemo.app/HDPodBMKDemo (0x1004ad708). One of the two will be used. Which one is undefined.

objc[10502]: Class BMSDKUDID is implemented in both /private/var/containers/Bundle/Application/B5A38F9D-E271-491C-B95D-6C05671D2332/HDPodBMKDemo.app/Frameworks/HDPodBMKSDK.framework/HDPodBMKSDK (0x100f95228) and /var/containers/Bundle/Application/B5A38F9D-E271-491C-B95D-6C05671D2332/HDPodBMKDemo.app/HDPodBMKDemo (0x1004ad758). One of the two will be used. Which one is undefined.

確實也在說明兩邊都有百度地圖這個鬼東西。

當然不能每次在pod update HDPodBMKSDK 重新勾選百度地圖到 HDPodBMKSDK中,腳本來解決(主工程中的Podfile中):

# http://www.rubydoc.info/gems/cocoapods/Pod/Project

post_install do |installer|
    project_location = './Pods/Pods.xcodeproj'
    # 設置使用#{framework_names}對應的target
    target_names = ['HDPodBMKSDK']
    framework_names = [ 'BaiduMapKit' ]

    project = installer.pods_project

    framework_names.each do |framework_name|
        frameworks = project.pod_group(framework_name)
        .children
        .find { |group| group.name == 'Frameworks' }
        .children

        target_names.each do |target_name|
            target = project.targets.find { |target| target.to_s == target_name }
            frameworks_group = project.groups.find { |group| group.display_name == 'Frameworks' }
            frameworks_build_phase = target.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }

            frameworks.each do |file_ref|
                frameworks_build_phase.add_file_reference(file_ref)
            end
        end
    end
end

或者在工程的 Pods.xcodeproj 同級路徑下,添加一個 ruby 腳本:podTaget.rb :

# https://github.com/CocoaPods/Xcodeproj/issues/408

require 'xcodeproj'

#project related valus
project_path = "/Users/denglibing/project/harryProject/HDPodBMKDemo/Pods/Pods.xcodeproj"
target_name = "HDPodBMKSDK"
project = Xcodeproj::Project.open(project_path)
target = project.targets.find { |target| target.to_s == target_name }
frameworks_build_phase = target.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
frameworks_group = project.groups.find { |group| group.display_name == 'Frameworks' }

baidusdk_framework_path = "/Users/denglibing/project/harryProject/HDPodBMKDemo/Pods/BaiduMapKit/BaiduMapKit/thirdlibs/"
framework_names = [
'BaiduMapAPI_Base.framework',
'BaiduMapAPI_Cloud.framework',
'BaiduMapAPI_Location.framework',
'BaiduMapAPI_Map.framework',
'BaiduMapAPI_Radar.framework',
'BaiduMapAPI_Search.framework',
'BaiduMapAPI_Utils.framework',
]


# Add framework to target as "Linked Frameworks"
framework_names.each do |framework_name|
    framework_ref = frameworks_group.new_file("#{baidusdk_framework_path}/#{framework_name}")
    frameworks_build_phase.add_file_reference(framework_ref)
end

# Save the project
project.save()

或者簡單的來,在包含百度地圖的pod的 podspec中,寫好如下的代碼(關鍵代碼):

s.frameworks   = "CoreLocation", "CoreTelephony", "OpenGLES", "QuartzCore", "Security", "SystemConfiguration", "BaiduMapAPI_Base", "BaiduMapAPI_Cloud", "BaiduMapAPI_Location", "BaiduMapAPI_Map", "BaiduMapAPI_Radar", "BaiduMapAPI_Search", "BaiduMapAPI_Utils"
s.libraries    = "z", "sqlite3.0", "stdc++.6.0.9", "crypto", “ssl"
s.pod_target_xcconfig = {
        'FRAMEWORK_SEARCH_PATHS'   => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit',
        'LIBRARY_SEARCH_PATHS'     => '$(inherited) $(PODS_ROOT)/BaiduMapKit/BaiduMapKit/thirdlibs',
        'OTHER_LDFLAGS'            => '$(inherited) -undefined dynamic_lookup -lObjC',
        'ENABLE_BITCODE'           => 'NO'
}

3.2、framework包含百度地圖,幫助主工程完成百度地圖相關代碼,這個肯定可行,但是感覺不怎么通用。畢竟framework不能實現主工程的代碼邏輯吧

3.3、放棄Cocoapods管理framework,自己打包加入到主工程中。這個可行,從打包后的結構看出主項目的二進制并沒有百度地圖相關代碼,它們存在framework中

方案可行。

4、下面是測試的代碼地址:

主項目和framework都是通過Cocoapods來依賴百度地圖sdk:

制作的framework工程地址: https://github.com/erduoniba/HDPodBMKSDK

項目主工程地址:https://github.com/erduoniba/HDPodBMKDemo

這樣其實兩邊都是有百度地圖sdk的代碼的,造成項目體積變大,雖然我測試過程中Xcode只是提示 One of the two will be used. Which one is undefined 運行沒有問題,但是是否存在一些隱性的問題還待發現。

5、其他

同樣的,經過我的實驗(不用Cocoapods管理),動態庫HDFramework2是可以嵌入HDFramework3(二進制未嵌入,HDFramework3二進制還是存在HDFramework3.framework中)的,在主工程HDFrameworkDemo中只需要有HDFramework2即可; 項目打包后結構:

HDFramework2如何嵌入HDFramework3:

同樣的,經過我的實驗,靜態庫HDFramework2是可以嵌入HDFramework3(二進制未嵌入)的,在主工程HDFrameworkDemo中需要有HDFramework2,同時link HDFramework3; 項目打包后結構:

主工程HDFrameworkDemo需要 link HDFramework3:

ruby庫xcodeproj使用心得

http://www.lxweimin.com/p/cca701e1d87c

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容