最近一段时间,我的团队基于uniapp开发的平台型APP因平台资金合规的要求,需要对接中金支付,uniapp的插件市场有一个别人做好的中金支付插件,但前端开发同事在引用这个 插件时,出现了 iOS APP 打包不成功的情况,开发花了几天时间也没有解决问题,就上升到我这边处理了。
由于我们的 APP大小已经超过 40MB,每次云打包都要收10元打包费用,让前端开发通过砍代码的方式,写了一个 小于 40MB 可以复现问题的 demo APP,这样我就可能通过多次打包一次一次调整并接近问题的核心。
这个demo APP是使用了 APP分享到微信的功能 和 一个中金支付的插件,也正是这 2 个功能触发了本次的问题。
第一次打包失败,看下面问题的现像,明显就是 Undefined symbols,一看就知道是 链接阶段,链接器找不到库,相关的 symbols自然就链接失败了。
cd [PackagePath]
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target arm64-apple-ios12.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk -Os -L[PackagePath]/build/EagerLinkingTBDs/Release-iphoneos -L[PackagePath]/build/Release-iphoneos -L[SourcePath]/libs/UniSDK/Base -L[SourcePath]/libs/UniSDK -L[PackagePath]/utsFrameworks -L[SourcePath]/libs/Universal/DCUniAdWm.xcframework/ios-arm64/ -L[PackagePath]/wgtRoot/__UNI__0278D71/nativeplugins/cpcn-cpcnpay/ios/ -L[SourcePath]/libs/Universal -F[PackagePath]/build/EagerLinkingTBDs/Release-iphoneos -F[PackagePath]/build/Release-iphoneos -F[SourcePath]/libs/UniSDK/Base -F[SourcePath]/libs/UniSDK -F[PackagePath]/utsFrameworks -F[SourcePath]/libs/Universal/DCUniAdWm.xcframework/ios-arm64/ -F[PackagePath]/wgtRoot/__UNI__0278D71/nativeplugins/cpcn-cpcnpay/ios/ -F[SourcePath]/libs/Universal -F[SourcePath]/libs/UniSDK/Base -F[SourcePath]/libs/UniSDK -F[PackagePath]/utsFrameworks -F[SourcePath]/libs/Universal/DCUniAdWm.xcframework/ios-arm64/ -F[PackagePath]/wgtRoot/__UNI__0278D71/nativeplugins/cpcn-cpcnpay/ios/ -F[SourcePath]/libs/Universal -filelist [PackagePath]/build/HBuilder.build/Release-iphoneos/HBuilder.build/Objects-normal/arm64/HBuilder.LinkFileList -Xlinker -rpath -Xlinker @executable_path/Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker [PackagePath]/build/HBuilder.build/Release-iphoneos/HBuilder.build/Objects-normal/arm64/HBuilder_lto.o -fobjc-arc -fobjc-link-runtime -ObjC -ld64 -weak_framework SwiftUI -llibAdSupport -llibLoader -llibAccelerometer -lopencore-amrnb -lmp3lame -llibMedia -llibCache -llibLog -llibIO -llibPGInvocation -llibNativeObj -llibNativeUI -llibNavigator -llibPGProximity -llibStorage -llibUI -llibXHR -llibZip -llibShare -lweixinShare -lWeChatSDK -weak_framework AdSupport -weak_framework AppTrackingTransparency -weak_framework Accelerate -weak_framework AudioToolbox -weak_framework AVFoundation -weak_framework CFNetwork -weak_framework CoreFoundation -weak_framework CoreGraphics -weak_framework CoreMedia -weak_framework CoreTelephony -weak_framework CoreText -weak_framework CoreVideo -weak_framework Foundation -weak_framework ImageIO -weak_framework JavaScriptCore -weak_framework MobileCoreServices -weak_framework MediaPlayer -weak_framework QuartzCore -weak_framework QuickLook -weak_framework Security -weak_framework SystemConfiguration -weak_framework UIKit -weak_framework WebKit -lc++ -lz -lxml2 -lsqlite3 -weak_framework MetalKit -weak_framework GLKit -licucore -liconv -weak_framework DCUniAdWm -weak_framework CoreMotion -weak_framework CPCNWeixinPaySDK -weak_framework CPCNPayUniPlugin -weak_framework CPCNAlipaySDK -weak_framework AlipaySDK -weak_framework DCUniBase -Xlinker -no_adhoc_codesign -Xlinker -dependency_info -Xlinker [PackagePath]/build/HBuilder.build/Release-iphoneos/HBuilder.build/Objects-normal/arm64/HBuilder_dependency_info.dat -o [PackagePath]/build/Release-iphoneos/HBuilder.app/HBuilder
ld: warning: -ld64 is deprecated, use -ld_classic instead
ld: warning: arm64 function not 4-byte aligned: _dc_ffi_call_SYSV from [SourcePath]/libs/UniSDK/liblibPGInvocation.a(sysv_arm64.o)
ld: warning: arm64 function not 4-byte aligned: _ffi_closure_SYSV from [SourcePath]/libs/UniSDK/liblibPGInvocation.a(sysv_arm64.o)
Undefined symbols for architecture arm64:
\"_OBJC_CLASS_$_PayReq\", referenced from:
objc-class-ref in CPCNWeixinPaySDK(CPCNWeixinPay.o)
\"_OBJC_CLASS_$_PayResp\", referenced from:
objc-class-ref in CPCNPayUniPlugin(CPCNPayPluginProxy.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
以下是排查过程的记录汇总:
通过观察插件目录发现有一个 ios-exclude.txt。搜索后了解到 ios-exclude.txt 文件正是用于在 uniapp 云端打包时控制 链接器不链接哪些库的。打开 ios-exclude.txt 看到他 排除了 libWeChatSDK_pay.a 这个库。
前面的报错说 找不到 _OBJC_CLASS_$_PayReq 的定义,直觉判断 这个定义应该在 libWeChatSDK_pay.a 这个库中。使用 llvm-nm 命令证实了我的判断。下一步是 清空 ios-exclude.txt 再打一次包。
这一次仍然打包不成功,但看到的错误如下:
duplicate symbol '_OBJC_IVAR_$_WechatAuthSDK._status' in:
[SourcePath]/libs/Universal/libWeChatSDK.a(WechatAuthSDK.o)
[PackagePath]/wgtRoot/__UNI__0278D71/nativeplugins/cpcn-cpcnpay/ios//libWeChatSDK_pay.a(WechatAuthSDK.o)
意思是,引入了 libWeChatSDK_pay.a后,链接器发现了一些 symbol 重复定义在 2 个库中,如 libWeChatSDK.a、libWeChatSDK_pay.a,观察发现这 2 个库的区别就是 带不带 _pay。现在看来插件的作者是 ios-exclude.txt 中排除 libWeChatSDK_pay.a 这个库一定是有他自己的考虑。
百度搜索 libWeChatSDK.a、libWeChatSDK_pay.a的区别,得到的信息如下:
(1)libWeChatSDK_pay.a 为带支付功能的微信SDK,支持微信分享、微信支付及微信授权登录功能,直接导入libWeChatSDK_pay.a即可,忽略libWeChatSDK.a,不要两个同时导入。
(2)libWeChatSDK.a 为不带支付功能的SDK,仅支持微信分享和授权登录(不要导入此SDK)
意思是 这 2 个 库 除开 支付相关的函数symbol外,其它的功能/函数/symbol 是一样的。
再来能过 vimdiff 看一下 前后 2 次错误的对比,可以看到 第二次 错误是 云端打包时 clang 同时链接了 -lWeChatSDK -lWeChatSDK_pay 这 2 个库,当然会出现 一些 symbol 重复了。
到了这里,解决问题的思路已经清晰了:
1)uniapp 官方一定是 解决了 -lWeChatSDK -lWeChatSDK_pay 这 2 个库 同时引用时应该 改为 只引用 -lWeChatSDK_pay的问题,不然它们都推不出 uniapp这个产品
2)我们只能触发云端打包,不能直接决定云端 clang 的命令行参数,对于这个问题我们手上只有 2 个工具:
2.1 插件目录中的 ios-exclude.txt 文件
2.2 1)中提到的 官方方案。
这时出现了一个小插曲,后面再说。
通过如下组合 2.1、2.2 这 2 个工具成功解决了问题。
原来 HBuilderX 只勾选了"Share(分享)",云端打包时 clang 会使用 -lWeChatSDK 链接这个库。现在 HBuilderX 再勾选了"Payment(支付)" 云端打包时 clang 会使用 lWeChatSDK_pay 链接这个库。
同时引入这 2 个库会出现 duplicate symbol 符号重复的问题,但上面的 1)中已经猜到了 uniapp 官方一定是 解决了-lWeChatSDK -lWeChatSDK_pay 这 2 个库 同时引用时应该 改为 只引用 -lWeChatSDK_pay,不然它们都推不出 uniapp这个产品。
所以这次解决问题的思路是找到问题的核心,再利用 官方的工具/方式/组合 去解决问题。
-----------------------------------------------------------------
说一下前面的小插曲,文章记录的只是打包 2 次就发现了问题的核心,但实际上我是多点击了几次打包,应该打包了 10次,然后 uniapp的提示时今天免费打包的次数太多,明天再能再次使用免费打包,或者可以选择10元打包一次。当天正好也是晚上 21:00 之后了,就下班回家了,但内心中有一种莫名的高兴,笃定了问题的解决方案就是 : HBuilderX 再勾选了"Payment(支付)" ,利用 官方的工具/方式/组合 去解决问题,坚信明天上班后第一次打包就能解决问题。
对自己知识和方法的确定,是工作中快乐的来源。