iOS: 由第三方SDK引起 duplicate symbol 的思考

本文详细探讨了在iOS App开发中,接入第三方SDK时遇到的duplicate symbol问题,通过使用ar和lipo工具分析和解决,特别以百度地图SDK为例,解析了如何识别和解决fat文件中的架构冲突,以及如何避免自定义代码与第三方库命名冲突导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文建立在 xcode6.4 的基础之上.

开发 App, 难免要接第三方的 SDK. 按照 SDK 文档接入, 理论上说不会有什么错误.

~

但是, 现实还是没那么的理想~

~

第三方 SDK 一般不会写文档告诉你, 我使用了哪些第三方库, 你们在接入的时候要注意啊类似的话.

可能说出这样的话, 无法体现自己的逼格, 呵呵!

这样就苦逼了程序员们了.

不过, 魔高一尺道高一丈!

~

今天讨论一下接入 SDK 引起的 duplicate symbol 问题.

拿百度地图来说吧. 

不是黑百度地图, 确实是自己亲身经历.

~

按照百度地图的接入文档, 顺利的完成了开发!

后面随着项目的完善, 自己也加入了一些开源库, 比如 Reachability.

加入之后, 项目编译链接就失败了.

~

这时, 我就开始怀疑是百度地图 SDK 引起的. 于是开始了下面的旅程.

~

这里会用到 ar 和 lipo 工具.不知道他们用法的可以自行 google.

ar 工具可以列出库文件中的相关文件.

ar -t BaiduMapAPI.framework

提示信息(失败``)

ar: BaiduMapAPI.framework: Inappropriate file type or format

提示的意思是, 无法识别(不兼容).

cd BaiduMapAPI.framework/

ar -t BaiduMapAPI

还是提示失败

ar: BaiduMapAPI is a fat file (use libtool(1) or lipo(1) and ar(1) on it)
ar: BaiduMapAPI: Inappropriate file type or format

这次的提示给了一条明路: is a fat file.

既然他是 fat 的, 那么如何 thin 下来呢?

我在这里找到了答案, 你可以点击看看.

~

使用 lipo 将其瘦身.

首先, 看一下 BaiduMapAPI.framework 支持哪些架构.

如果你像下面这样操作的话

 lipo -info BaiduMapAPI.framework

出现一个错误提示

can't map input file: BaiduMapAPI.framework (Invalid argument)

答案在这里:iOS Framework lipo报错 lipo: can't map input file

cd BaiduMapAPI.framwork

lipo -info BaiduMapAPI

成功的输出信息

Architectures in the fat file: BaiduMapAPI are: armv7 armv7s i386 x86_64 arm64 

说明, 这个库既支持模拟器(i386 | x86_64), 又支持真机(armv7 | armv7s | arm64).

关于 iphone 和 ipad 的CPU架构, 可以参考这张(叼炸天)的图.



原图来源自这里:点击打开链接.

~

接下来, 我们开始提取其中一种架构来分析.

lipo BaiduMapAPI -thin armv7 -output bmap.armv7
在当前路径下, 生成了 bmp.armv7文件.

ar -t bmap.armv7 
可以看一下 list

__.SYMDEF
Animation.o
AppLocation.o
AppMan.o
BGLBase.o
BGLLine.o
BGLModel.o
BGLSurface.o
BGLTextrue.o
BMAddrList.o
BMAddressInfo.o
BMAppTools.o
BMAreaSearchResult.o
BMAroundInfo.o
BMBase.o
BMBusLine.o
BMBusLineElement.o
BMBusRoute.o
BMCarRoute.o
BMCityInfo.o
BMCityList.o
BMCloudEngine.o
BMCloudSerail.o
BMDictionary.o
BMEspecialQuery.o
BMGEOResult.o
BMHeatMapOverlay.o
BMHeatMapService.o
BMHistoryKeyWords.o
BMKActionPaopaoView.o
BMKAnnotationView.o
BMKAnnotationViewInternal.o
BMKArcline.o
BMKArclineView.o
BMKBaseCloudSearchInfo+Interval.o
BMKBusLineSearch.o
BMKBusLineSearchOption.o
BMKCircle.o
BMKCircleView.o
BMKCloudPOIList.o
BMKCloudSearch.o
BMKCloudSearchInfo.o
BMKGeocodeSearch.o
BMKGeocodeSearchOption.o
BMKGeocodeType.o
BMKGeometry.o
BMKGradient+Interval.o
BMKGradient.o
BMKGroundOverlay.o
BMKGroundOverlayView.o
BMKHeatMap.o
BMKLocationService.o
BMKLocationServiceInternal.o
BMKLocationViewDisplayParam.o
BMKManager.o
BMKMapStatus.o
BMKMapView.o
BMKMultiPoint.o
BMKNavigation.o
BMKNotificationCenter.o
BMKNotifier.o
BMKOfflineMap.o
BMKOfflineMapType.o
BMKOverlayGLBasicView.o
BMKOverlayPathView.o
BMKOverlayView.o
BMKOverlayViewInternal.o
BMKPinAnnotationView.o
BMKPoiSearch.o
BMKPoiSearchOption.o
BMKPoiSearchType.o
BMKPointAnnotation.o
BMKPolygon.o
BMKPolygonView.o
BMKPolyline.o
BMKPolylineView.o
BMKRouteInternal.o
BMKRouteSearch.o
BMKRouteSearchOption.o
BMKRouteSearchType.o
BMKShape.o
BMKShareURLSearch.o
BMKShareUrlSearchOption.o
BMKSuggestionSearch.o
BMKSuggestionSearchOption.o
BMKTypes.o
BMKUserLocation.o
BMKUserLocationInternal.o
BMLogService.o
BMMapMsgObserver.o
BMMapViewManager.o
BMOfflineCityInfo.o
BMOnlineUpData.o
BMPOIDetail.o
BMPOIInfo.o
BMPOIList.o
BMPlaceParameterInfo.o
BMPoiBkgData.o
BMPointQuadTree.o
BMReachability.o
BMReverseGEOResult.o
BMSDKDeviceInfo.o
BMSDKKeychainItemWrapper.o
BMSDKUDID.o
BMSearchEngine.o
BMSerail.o
BMSubwayLineInfo.o
BMTile.o
BVDBBase.o
BVDBBuffer.o
BVDBLog.o
BVDBMission.o
BVDBToolkit.o
BVDBUrl.o
BVDDBase.o
BVDDCache.o
BVDDDataTMP.o
BVDDDataset.o
BVDDToolkit.o
BVDEDataCfg.o
BVDEDataDOM.o
BVDEDataEngine.o
BVDEDataHEM.o
BVDEDataITS.o
BVDEDataMap.o
BVDHBase.o
BVDHCache.o
BVDHDataTMP.o
BVDHDataset.o
BVDHToolkit.o
BVHEMMission.o
BVIDBase.o
BVIDCache.o
BVIDDataEVT.o
BVIDDataTMP.o
BVIDDataVMP.o
BVIDDataset.o
BVIDOfflineFrame.o
BVIDToolkit.o
BVMDBase.o
BVMDCache.o
BVMDDataTMP.o
BVMDDataVMP.o
BVMDDataset.o
BVMDFrame.o
BVMDIndex.o
BVMDToolkit.o
BaiduMapView.o
Baidu_Reachability.o
BaseFramework_vers.o
BaseLayer.o
BaseLayerData.o
BaseMapFactory.o
BaseMapScaleView.o
BaseOverlay.o
BundleUtil.o
CRT.o
CVDatabase.o
CVNetworkStatusMonitor.o
CVResultSet.o
CVStatement.o
CloudControl.o
CloudSearch.o
CloudSearcher.o
CommonMemCacheEngine.o
CommonToolJsonPharser.o
CommonToolSearch.o
CommonToolSearchUrl.o
CompassOverlay.o
CompassView.o
ComplexPt.o
DataStorage.o
DetailJsonObjParser.o
DetailSearch.o
DetailSearchUrl.o
DrawUnit.o
EAGLView.o
FrameControl.o
GDI_Bitmap.o
GDI_FontMan.o
GDI_FontTrueType.o
GDI_Line.o
GDI_Res.o
GDI_Surface.o
GDI_Util.o
GZipHelper.o
GZipUtil.o
GridData.o
GridDataCache.o
GridDataFileCache.o
GridLayer.o
GroundData.o
GroundLayer.o
GroundOverlay.o
HardwareInfo.o
HeatmapData.o
HeatmapLayer.o
HttpClientPool.o
IphoneBaiduMaps.o
IphoneGPSMan.o
JsonPharser.o
LBSSearchFramework_vers.o
LocalCityInfo.o
LocalMap.o
LocalMapElement.o
LocalMapEngine.o
LocalMapImport.o
LocalMapImportElemInfo.o
LocalMapInfo.o
LocationController.o
LocationEngine.o
LocationFramework_vers.o
LocationView.o
MapController.o
MapDefine.o
MapFramework_vers.o
MapGesture.o
MapModeEngine.o
MapModel.o
MapView.o
MyUIDeviceIdentifierAddition.o
NSStringMD5Addition.o
NetworkDetectEngine.o
PaopaoBaseView.o
PoiJsonPharser.o
PoiMarkData.o
PoiMarkExtData.o
PoiMarkExtLayer.o
PoiMarkLayer.o
PoiSearch.o
PoiSearchUrl.o
ResPackFile.o
RoutePlanJsonPharser.o
RoutePlanSearch.o
RoutePlanSearchUrl.o
SDKHeatMapLayer.o
SDKHeatMapLayerData.o
SDKHeatMapLayerDataModel.o
SearchControl.o
SearchFramework_vers.o
Searcher.o
SpatialUtil.o
StretchImageUtil.o
Style.o
SugSearchJsonObjParser.o
SuggestionResult.o
SuggestionSearch.o
SuggestionSearchUrl.o
SysConfig.o
SysConfigMan.o
TapDetectingView.o
TrafficData.o
TrafficEventData.o
TrafficEventLayer.o
TrafficLayer.o
UIDeviceHelper.o
UIDeviceScreen.o
UtilsFramework_vers.o
VBGL.o
VBase.o
VBaseMapLayerFactory.o
VBaseMapPoiLayerFactory.o
VBundle.o
VCMMap.o
VComServer.o
VCommonMemCacheFactory.o
VCommonToolSearchFactory.o
VDNSCache.o
VDataEngineFactory.o
VDataStorageFactory.o
VDetailSearchFactory.o
VDeviceAPI.o
VException.o
VF_Face.o
VF_Glyph.o
VF_Module.o
VF_Render.o
VF_TT_Outline.o
VF_TT_Table.o
VFile.o
VGDI.o
VGroundLayerFactory.o
VHeatmapLayerFactory.o
VHttpClient.o
VHttpClientPoolFactory.o
VHttpGet.o
VHttpPost.o
VHttpRequestBase.o
VHttpResponse.o
VHttpSocket.o
VLocationFactory.o
VLog.o
VMapControl.o
VMapSimple.o
VMem.o
VMemAlloc.o
VMemPool.o
VMsg.o
VNetStateObservable.o
VNetStateObserver.o
VNetworkDetectFactory.o
VOSJpeg.o
VOSPng.o
VPoiSearchFactory.o
VRoutePlanSearchFactory.o
VSDKHeatMapLayerFactory.o
VSearchFactory.o
VServerForwardFailOverFactory.o
VServerForwardFailover.o
VSocket.o
VString.o
VStyleFactory.o
VSuggestionSearchFactory.o
VSysConfigFactory.o
VThread.o
VTimer.o
VTrafficEventLayerFactory.o
VTrafficLayerFactory.o
VUrlUtility.o
VVos.o
VWnd.o
adler32.o
cJSON.o
compress.o
crc32.o
deflate.o
des.o
encrypt.o
envpostmsg.o
fcrypt.o
gpc.o
gzclose.o
gzgpst.o
gzlib.o
gzread.o
gzwrite.o
infback.o
inffast.o
inflate.o
inftrees.o
ioapi.o
jaricom.o
jcapimin.o
jcapistd.o
jcarith.o
jccoefct.o
jccolor.o
jcdctmgr.o
jchuff.o
jcinit.o
jcmainct.o
jcmarker.o
jcmaster.o
jcomapi.o
jcparam.o
jcprepct.o
jcsample.o
jctrans.o
jdapimin.o
jdapistd.o
jdarith.o
jdatadst.o
jdatasrc.o
jdcoefct.o
jdcolor.o
jddctmgr.o
jdhuff.o
jdinput.o
jdmainct.o
jdmarker.o
jdmaster.o
jdmerge.o
jdpostct.o
jdsample.o
jdtrans.o
jerror.o
jfdctflt.o
jfdctfst.o
jfdctint.o
jidctflt.o
jidctfst.o
jidctint.o
jmemansi.o
jmemmgr.o
jmemnobs.o
jpegtran.o
jquant1.o
jquant2.o
jutils.o
md5.o
minixml.o
mztools.o
png.o
pngerror.o
pngget.o
pngmem.o
pngpread.o
pngread.o
pngrio.o
pngrtran.o
pngrutil.o
pngset.o
pngtrans.o
pngwio.o
pngwrite.o
pngwtran.o
pngwutil.o
rdbmp.o
rdcolmap.o
rdgif.o
rdjpgcom.o
rdppm.o
rdrle.o
rdswitch.o
rdtarga.o
sqlite3.o
systemConfigModel.o
transupp.o
trees.o
uncompr.o
unzip.o
util.o
wrbmp.o
wrgif.o
wrjpgcom.o
wrppm.o
wrrle.o
wrtarga.o
zip.o
zutil.o

~

可以看出果然有 Baidu_Reachability.o和 BMReachability.o.

解决方案就是, 删除自己项目中引用的 Reachability 这个库.

~

当然, 你也可以解压出这些文件, 使用下面命令

ar xv bmp.armv7

到此为止, 解决了其中一个错误, 希望大家初步清楚使用 lipo 和 ar 这两个工具.

另外还有一个错误, 也是 duplicate symbol.

跟大家分享一下.

这个错误的原因在于自己写的代码, 把一个结构体指针命名为 p, 和百度地图也重复了.

我修改了这个命名, 就编译成功了.

~

这里也暴露了几个问题:

1. 在写 sdk 的时候, 命名一定要加前缀.

2. 自己写的代码, 命名不要那么的随性.

3. sdk 使用了哪些第三方库, 最好告诉开发者.

~

不想看下面的, 就浏览完成了.

~

在此特别感谢: How to fix a "Duplicated Symbols" error on binary files 的作者!


附录:


* 了解 xcode 中关于 Architecture 和 valid architecture 的, 可以参考

1. 官方文档Build Setting Reference

2. Xcode设置项之Architectures和Valid Architectures


* 了解 xcode6 默认不支持 armv7s 和制作静态库注意事项的, 可以参考

1. Xcode 6 默认不再构建 Armv7s 指令集的代码

2. xCode6制作动态及静态Framework


* 学习 lipo, 可以借鉴

1. lipo 命令

2. lipo命令使用

3. lipo 制作通用版本静态库



<think>好的,我需要回答用户关于在iOS开发中同时使用Places SDK 9.3.0和Google Maps SDK 8.2.0时可能出现的兼容性问题。首先,我得回忆一下这两个SDK之间的关系和各自的依赖。 Google的SDK通常会有版本间的兼容性说明,但用户可能不会总是查看文档。我需要考虑几个方面:依赖库版本冲突、API变化、资源冲突、性能影响,以及认证问题。 首先,依赖库版本。如果两个SDK都依赖同一个库但不同版本,比如GoogleUtilities,可能会有冲突。例如,Places SDK 9.3.0可能使用GoogleUtilities 7.0而Maps SDK 8.2.0需要6.0,这会导致问题。 然后是API变更。虽然都是Google的产品,但不同版本的SDK可能修改了某些类或方法。例如,如果Maps SDK 8.2.0移除了某个类,而Places SDK 9.3.0还在使用,就会导致崩溃或错误。 资源文件冲突也有可能,比如两个SDK包含同名的资源文件,打包时会被覆盖,导致运行时问题。 性能方面,同时使用两个SDK可能会增加内存和启动时间,特别是如果它们都进行网络请求或初始化大量对象时。 另外,认证方面,两个SDK可能需要不同的API Key配置,或者同一个Key但有不同权限,需要确保正确设置。 建议用户查阅官方文档,使用CocoaPods或Swift Package Manager管理依赖,保持SDK版本同步,并测试关键功能。如果遇到问题,检查错误日志,降级或升级SDK版本,或者联系Google支持。 需要确保回答准确,同时用用户能理解的语言,避免技术术语过多。可能还需要提醒用户实际开发中最好保持两个SDK版本都为最新且相互兼容的版本,因为Google有时会同步更新相关SDK。</think>在 iOS 开发中同时使用 **Google Places SDK 9.3.0** 和 **Google Maps SDK 8.2.0**,可能会遇到以下兼容性问题及注意事项: --- ### 1. **依赖库版本冲突** - **问题**:两个 SDK 可能依赖不同版本的 Google 基础库(如 `GoogleUtilities`、`GoogleDataTransport` 等)。例如: - Places SDK 9.3.0 可能要求 `GoogleMaps/Base 7.0+` - Maps SDK 8.2.0 可能依赖 `GoogleMaps/Core 8.0+` - **表现**:编译时出现 `Undefined symbol` 或 `Duplicate interface` 错误。 - **解决**:使用 CocoaPods/Swift Package Manager 管理依赖,确保所有 Google SDK 的子组件版本一致。 --- ### 2. **API 行为不一致** - **问题**:不同版本的 SDK 可能修改了某些 API 的行为或参数。例如: - `GMSPlacesClient` 的方法签名或回调格式在跨版本时可能有变化。 - Maps SDK 8.2 可能弃用了某些 `GMSMapView` 的渲染配置。 - **表现**:运行时崩溃、回调不触发或功能异常。 - **解决**:查阅 Google 的 [版本迁移文档](https://developers.google.com/maps/documentation/ios-sdk/releases),对比两个 SDK 的变更记录。 --- ### 3. **资源文件冲突** - **问题**:两个 SDK 可能包含同名的资源文件(如图片、本地化文件),导致编译时被覆盖。 - **表现**:UI 显示异常(如地图标记图标错误)或本地化失效。 - **解决**:检查两个 SDK 的 `Resources` 目录,手动排除冲突文件(较少见)。 --- ### 4. **性能与内存问题** - **问题**:同时集成两个较大的 SDK 会增加包体积(可能增加 10-20MB),且初始化时占用更多内存。 - **表现**:App 启动变慢或低端设备上内存不足崩溃。 - **解决**:使用动态框架(如 XCFramework)或按需加载功能模块。 --- ### 5. **认证配置冲突** - **问题**:两个 SDK 可能需要不同的 API Key 配置或权限。 - **表现**:地图加载失败或 Places API 返回 `HTTP 403` 错误。 - **解决**:确保在 `AppDelegate` 中正确配置统一的 API Key,并在 Google Cloud 控制台启用所有相关服务(Maps SDK、Places API 等)。 --- ### 推荐实践 1. **使用最新兼容版本**:Google 通常会同步更新 Maps 和 Places SDK。例如: - Maps SDK 8.2.0 对应的推荐 Places SDK 是 9.3.0(两者是兼容的)。 2. **统一依赖管理**: ```ruby # CocoaPods 示例 pod 'GoogleMaps', '8.2.0' # Maps SDK pod 'GooglePlaces', '9.3.0' # Places SDK ``` 3. **测试关键场景**:重点测试地图渲染、地点搜索、自动完成等功能是否正常。 --- 如果遇到具体问题,建议通过 **Xcode 的调试控制台日志** 或 **Google 的错误代码文档** 定位原因。多数情况下,只要版本匹配且依赖正确,两者可以协同工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值