ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

uni-app iOS 免上架分发:证书、打包与 OTA 安装指南

uni-app iOS 免上架分发:证书、打包与 OTA 安装指南 1. 先想清楚为什么要绕开 App Store 做 iOS 分发做 uni-app 的朋友大概都遇到过这个场景项目本身是给内部员工用的巡检工具或者给一小批种子用户试用的 MVP功能已经跑通了用 HBuilderX 打完包拿到了 ipa结果卡在最后一步——上架审核要时间、要资质、要各种合规材料而业务方明天就想让用户装到手机上。这时候不上架 App Store、直接把 ipa 给用户下载就成了一条现实路径。但这条路不是把 ipa 丢到网盘里发个链接就完事的。iOS 和 Android 在这一步的差别相当于随手把 APK 发给别人安装和你要先向苹果证明这台设备有资格装这个包的差别。iOS 的每一份 ipa 都绑定了签名证书和描述文件描述文件决定了这个包能装在哪些设备上、能装多久、需不需要用户手动信任。所以真正要解决的问题有三个用哪种账号和证书签、怎么把包打出来、怎么让用户用一个链接就装上。这三个问题任何一个没搞清楚用户看到的都是无法安装此 App。这篇记录面向的是已经能用 uni-app 跑通业务、但对 iOS 签名生态不太熟的开发者。不管你是第一次接触 iOS 分发还是之前用第三方签名平台掉过签想换成自建方案下面这套流程都可以直接照着走。我会把每一步为什么这么做讲透也会把那些官方文档里不会写、但实际会卡住你半天的地方标出来。1.1 三条主流分发路径的真实差别很多人一上来就问企业证书怎么搞其实先该问的是我的用户是谁。路径选错的代价可能是几千块钱和几周的返工。Ad Hoc 分发是门槛最低的一种。它用你个人或公司开发者账号99 美元/年里的 Ad Hoc 类型描述文件把指定设备的 UDID 写进描述文件里只有这些设备能装。优点是不需要苹果审核、当天就能发缺点是设备数量有硬上限每个会员年每种设备类型最多 100 台而且换手机、加新人就要重新生成描述文件、重新打包。适合内部几十人规模的小团队。企业账号In-House分发是大家最想要的方案299 美元/年不需要收集 UDID描述文件里没有设备限制理论上公司内部任意设备都能装。代价是申请门槛高——需要公司实体、D-U-N-S 编码苹果会核查你的企业资质和使用场景而且明确规定只能给公司内部人员使用。一旦被判定为对外公开分发证书会被直接吊销所有已安装的设备会立刻打不开应用。这点必须有心理准备别把企业证书当成万能分发通道。TestFlight是苹果官方认可的测试分发方式完全免费通过 App Store Connect 上传构建版本外部测试员上限 10000 人每个构建版本有效期 90 天。它需要过一次 TestFlight 审核比正式上架宽松很多通常一两天而且用户需要在手机上装 TestFlight 这个 App。如果你的场景是给一批真实用户试用但不想正式上架TestFlight 其实是合规性最好的选择只是流程上多了一个外部 App。1.2 成本和时间账先算清楚再动手维度Ad Hoc企业账号 In-HouseTestFlight年费99 美元299 美元0需 99 美元开发者账号申请难度低注册即可高需企业资质审核低设备限制每类 100 台需 UDID无10000 名测试员有效期描述文件 1 年描述文件 1 年构建 90 天苹果审核无无有但较宽松用户操作需信任描述文件需信任企业开发者装 TestFlight 后点安装合规风险低中高严禁外部分发低还有一个经常被问的问题uni-app 打包 iOS 收费吗。这里要拆成两笔账。第一笔是苹果那边的开发者账号的年费跑不掉个人/公司 99 美元企业 299 美元。第二笔是 HBuilderX 的云打包服务免费额度有限超过之后需要购买打包次数如果你选择本地离线打包用 Xcode 自己编译就不产生这笔费用代价是环境搭建更麻烦。我的建议是项目初期用云打包快速验证等发版频率上来了再考虑离线打包。1.3 我的一般选择顺序如果是 20 人以内的内部工具Ad Hoc 就够了最省心出问题也好排查。如果是几百人的公司全员使用且有正规企业资质走 In-House但一定要在内部明确不对外分享安装链接。如果是要面向真实用户做灰度别硬上企业证书老老实实走 TestFlight能省掉后面一大堆掉签的麻烦。至于第三方签名平台那条路我个人不推荐——这类平台本质上是拿别人的证书给你的包重签名证书什么时候被吊销你完全不知道用户昨天还能用今天打开就闪退售后成本极高而且合规上存在明显风险。顺带说一句像微信多开自签包这类应用本身就处在灰色地带技术上怎么实现是另一回事但作为开发者要清楚自己在承担什么。2. 证书与描述文件打包前最容易翻车的一步我见过太多人卡在这一步HBuilderX 里填完 Bundle ID 和证书一点打包报证书与描述文件不匹配然后开始在网上乱搜。问题的根源通常是没搞清楚 iOS 签名体系里那几个文件分别是什么、谁和谁必须对应。一句话概括这套体系证书Certificate证明你是谁描述文件Provisioning Profile规定你能把 App 装到哪两者通过 App ID 绑定在一起任何一环对不上包就装不进去。2.1 三种证书分别用来干什么打开苹果开发者后台的 Certificates 页面你会看到几种类型别选错。Apple Development是开发证书配合开发描述文件用来在 Xcode 里真机调试。它的描述文件里必须包含测试设备的 UDID。Apple Distribution是发布证书用于 App Store 提交和 Ad Hoc 分发这是你要发 ipa 给别人装的时候用的。Apple Push Services是推送证书只有你用推送功能时才需要单独生成注意它和发布证书是两回事别混。还有一类是企业账号特有的In-House 描述文件在 Profiles 页面创建时Distribution Method 选 In House不需要勾选任何设备。这里有个细节值得单独说很多人手里的 .p12 是从别人那儿拷来的或者从某台旧电脑导出的密码早就忘了。建议每个项目单独生成一套证书用 1Password 之类的工具把 .p12 和密码一起存起来导出的 .p12 一定要设密码因为 HBuilderX 打包时会让你填这个密码。证书丢了不用慌去后台 Revoke 掉重新生成就行但要注意 Revoke 会影响所有用这张证书签的 App如果线上还有在用的包尽量在低峰期操作。2.2 在开发者后台把 p12 和 mobileprovision 拿到手完整流程大概是这样我第一次做的时候前后花了两个小时第二次十分钟就搞定了。第一步创建 App ID。在 Identifiers 页面新建一个Bundle ID 建议用反向域名比如com.yourcompany.inspection。如果项目里用到了推送、iCloud、Associated Domains 这些能力记得在这里勾上对应的 Capabilities。Bundle ID 一旦确定就别再改改了等于换了一个新 App用户装上去会是两个图标。第二步生成证书。在 Certificates 页面点加号选 Apple Distribution然后按提示在本地生成 CSR 文件Mac 上用钥匙串访问的证书助理就能生成。上传 CSR 后下载 .cer 文件双击导入钥匙串在钥匙串里找到这张证书右键导出为 .p12设一个密码。这个 .p12 就是 HBuilderX 要的那个私钥证书。第三步生成描述文件。在 Profiles 页面新建选 Ad Hoc 或 In House绑定刚才的 App ID 和证书Ad Hoc 还要勾选设备。下载下来的 .mobileprovision 文件就是描述文件。这里有个非常容易踩的坑描述文件的命名是 xxx.mobileprovision但它在描述文件列表里显示的名字Name 字段和文件名不是一回事。HBuilderX 上传时读的是文件本身所以不要手动改文件后缀也别用文本编辑器打开另存那样会把二进制结构破坏掉。2.3 描述文件里那 100 台 UDID 怎么加Ad Hoc 最烦的就是这一步。用户需要把设备 UDID 给你获取方式有好几种在 Mac 上连数据线用 Finder 看、用 iTunes 看序列号那栏点一下切换成 UDID、或者让用户自己装一个描述文件生成工具。iOS 16 之后苹果还在设置里加了一个开发者模式开关真机调试的时候要单独打开这个后面讲排查问题时会再提到。拿到 UDID 后在开发者后台的 Devices 页面添加注意区分 iPhone、iPad 等设备类型每类独立计数。加完设备必须回到描述文件里编辑勾上新增的设备然后重新下载描述文件否则新设备还是装不上。这个改完设备忘更新描述文件的错误我至少犯过三次。还有个隐藏限制设备从账号里移除之后同一个 UDID 在本会员年度内不能再次添加。所以清理设备列表的时候要谨慎别手快把还在用的设备删了。3. uni-app 工程侧要改的东西证书准备好了接下来是工程本身。uni-app 的特点是大部分配置集中在 manifest.json 里打包工具会把它翻译成 iOS 工程里的 Info.plist 和 entitlements。这个自动翻译很方便但也意味着你填错的地方不会报错而是会在用户手机上以闪退的形式暴露出来。3.1 manifest.json 里与 iOS 强相关的几个节点在 HBuilderX 里打开 manifest.json切到App 图标配置和App 模块配置之外重点是App 常用其他设置和源码视图。用源码视图看得更清楚结构大致是app-plus→distribute→ios。几个关键字段appid这里的 appid 是 DCloud 的 AppID和苹果的 Bundle ID 不是一回事别搞混。Bundle ID在打包时单独填写必须和描述文件里的 App ID 一模一样大小写敏感。deviceType控制支持 iPhone 还是 iPad。如果只支持 iPhone某些系统检查会认为 iPad 上是以兼容模式运行的需要注意。privacyDescription隐私权限描述下面单独讲。UIStatusBarStyle状态栏样式浅色背景配深色文字这类问题。deploymentTarget最低支持的 iOS 版本改高一点可以少踩老系统的坑但用户机型太旧就装不了。还有个容易被忽略的点manifest.json 里的版本号version.name和version.code就是 ipa 里的 CFBundleShortVersionString 和 CFBundleVersion。version.code必须是递增的整数如果做 wgt 热更新或者以后转上架版本号回退会带来一堆麻烦建议每次发版老老实实加一。3.2 权限描述写不好用户打开就闪退iOS 的隐私机制非常严格如果代码里调用了相册、相机、蓝牙、定位这类能力但 Info.plist 里没有对应的用途描述字符串系统会直接杀掉进程表现就是用户点开某个页面瞬间闪退而且不会有任何弹窗提示。这是 uni-app 项目上 iOS 之后最高频的闪退原因之一。在 HBuilderX 的 App 模块配置里如果你勾了蓝牙、相册、摄像头等模块打包界面会自动列出对应的隐私描述输入框。填的时候注意三点第一描述要写清楚具体用途不能写为了更好的体验这种空话。用户看到的是这句话写得不清楚容易被投诉审核的时候也会被挑。第二蓝牙相关的描述键名要用最新的。老版本用的是NSBluetoothPeripheralUsageDescription新系统要求用NSBluetoothAlwaysUsageDescription两个都写上最保险。这跟热词里uni-app ble ios 可以根据蓝牙 deviceid 建立连接吗这个问题的排查是同一类——先确认权限描述到位再谈连接逻辑。第三如果用了 IDFA广告标识符要额外填NSUserTrackingUsageDescription。纯内部工具别开 IDFA开了反而会触发 App Tracking Transparency 的弹窗影响体验。3.3 图标、启动图、版本号三个最容易被忽略的坑图标这块uni-app 支持一键生成全尺寸图标但要注意iOS 的图标不能有透明通道。PNG 带 alpha 通道的话打出来的包在部分系统版本上图标会显示成黑底或者直接白块。上传前用图片工具把透明背景填成实色能省掉一次返工。启动图Launch Screen在 iOS 上有硬性要求如果缺失App 在某些机型上会以非全屏模式运行看起来像黑边。uni-app 的启动图配置里可以选择自动生成或自定义小项目用自动生成就行但生成的图会带默认底色视觉上要能接受。版本号这件事我在上面提过这里补充一个实际场景做内部迭代的时候很多人懒每次打包都不改版本号。结果用户装了新版系统认为是同一个版本覆盖安装之后新旧代码混在一起出现一些莫名其妙的 bug。养成习惯每次打包前改 version.code哪怕只是内部测试。4. 打包实操HBuilderX 云打包与 Xcode 离线打包配置改完就可以打包了。uni-app 提供两条路云端打包和本地离线打包。前者快、省事后者灵活、可控。4.1 云打包完整流程记录在 HBuilderX 里点发行 → 原生 App-云打包弹窗里选 iOS然后按顺序填Bundle ID从开发者后台复制的 App ID逐字符核对。私钥证书选之前导出的 .p12 文件。私钥密码导出 .p12 时设的那个密码不是 Apple ID 密码。描述文件选 .mobileprovision 文件。如果勾选了支持 iPad记得确认描述文件里是否包含 iPad 设备Ad Hoc 场景下。点击打包后会进入排队等待时间取决于当前队列长度。打包成功后 HBuilderX 会提示 ipa 的下载地址同时邮箱里也会收到一份链接。几个实测下来的要点一是打包日志一定要看很多人只看打包成功四个字就关了其实日志里可能有权限描述缺失、模块冲突的警告。二是如果报证书和描述文件不匹配先检查 Bundle ID 是否完全一致再检查描述文件里的证书是不是你上传的那张。三是一次打包可以生成多个 ipa不同渠道包别拿到第一个就以为完事了。4.2 离线打包这条路什么时候值得走本地离线打包需要下载 uni-app 的 iOS 离线 SDK用 Xcode 打开官方提供的工程模板把HBuilder-Hello里的 www 目录替换成你的项目编译产物然后在 Xcode 里配置签名和证书。这条路的价值在于你能完全控制 Info.plist、能自己加原生插件、能调试原生层的崩溃、不受云打包次数限制。代价是环境搭建比较折腾——需要 macOS、对应版本的 Xcode、CocoaPods 要能正常拉依赖首次配置花上半天很正常。我的经验是如果项目里有原生插件比如自定义的蓝牙通信、离线地图云打包一旦出错你几乎无从下手这时候就必须上离线打包。反过来纯 H5 逻辑 官方模块的项目云打包完全够用。4.3 打包完先验签别急着发给用户这一步很多人跳过结果是把有问题的包发出去用户反馈装不上你再去一步步排查浪费的是双方时间。养成习惯ipa 拿到手先在本机验一遍。# 解压 ipa看内部结构 unzip -q app.ipa -d check ls check/Payload/ # 查看签名信息证书主体、Team ID、签名时间 codesign -dv --verbose4 check/Payload/YourApp.app # 查看内嵌的描述文件内容 security cms -D -i check/Payload/YourApp.app/embedded.mobileprovision第一条命令能看到 Payload 里 App 的实际名称。第二条命令的输出里重点看Authority签名用的证书名和TeamIdentifier。第三条命令会输出一大段 plist重点看三个字段ExpirationDate描述文件过期时间超过这个日期包就打不开了。ProvisionedDevicesAd Hoc 场景下必须能找到目标设备的 UDID。Entitlements→application-identifier格式是TeamID.BundleID核对一下和你的 Bundle ID 是否一致。如果这三项都对得上包基本没问题。这是我最推荐的一个习惯每次发版前跑一遍这个命令三十秒的事能挡掉八成以上的装不上工单。5. 自建 OTA 下载页让用户点一下就装上包有了怎么给用户Android 那句下载这个 APK 点安装在 iOS 上不成立。iOS 装非商店 App 走的是 OTAOver-The-Air方式核心是那个很多人见过但没研究过的itms-services协议。5.1 itms-services 到底是怎么工作的一句话说清楚当你在 Safari 里打开一个itms-services://开头的链接时系统会去下载链接参数里指定的那个 plist 文件从 plist 里读出 ipa 的下载地址、App 名称、图标地址然后弹窗问你要不要安装。你点确认系统就去下载 ipa 并安装到桌面上。所以整个分发链条是三个东西下载页 HTML用户点的地方 manifest.plist告诉系统去哪下 ipa 文件真正的包。三者缺一不可且都要放在 HTTPS 环境下。有两个硬性约束必须记住。第一这个链接必须在 Safari 或者系统浏览器里打开微信、QQ、钉钉的内置浏览器一律不支持只会报错或者没反应。所以给用户发链接的时候要提醒一句用 Safari 打开或者干脆在页面里加个引导。第二必须是 HTTPS而且证书得是受信任的 CA 签发的自签证书 iOS 不认。5.2 manifest.plist 的完整写法这个文件是个 XML 格式的 plist结构固定照着改就行。?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyitems/key array dict keyassets/key array dict keykind/key stringsoftware-package/string keyurl/key stringhttps://dl.yourdomain.com/app/app-1.0.0.ipa/string /dict dict keykind/key stringdisplay-image/string keyneeds-shine/key false/ keyurl/key stringhttps://dl.yourdomain.com/app/icon-57.png/string /dict dict keykind/key stringfull-size-image/string keyneeds-shine/key false/ keyurl/key stringhttps://dl.yourdomain.com/app/icon-512.png/string /dict /array keymetadata/key dict keybundle-identifier/key stringcom.yourcompany.inspection/string keybundle-version/key string1.0.0/string keykind/key stringsoftware/string keytitle/key string巡检助手/string /dict /dict /array /dict /plist几个要点。software-package里的 url 就是 ipa 的完整地址。bundle-identifier必须和 ipa 里实际的 Bundle ID 完全一致不一致的表现是安装时弹窗一闪而过、什么都没发生。bundle-version是显示给用户看的版本号写错不会导致安装失败但会显示成旧版本号容易被误判。两个图标的地址如果 404App 装完桌面图标会是白块——不影响使用但很难看建议还是配上。5.3 下载页和服务器怎么配下载页本身很简单!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title巡检助手 - 安装/title /head body h1巡检助手 v1.0.0/h1 p请在 Safari 浏览器中打开本页面后点击下方按钮安装。/p a hrefitms-services://?actiondownload-manifesturlhttps%3A%2F%2Fdl.yourdomain.com%2Fapp%2Fmanifest.plist 点击安装 /a /body /html注意url后面的地址做了 URL 编码冒号和斜杠被转义这一步不做的话某些情况下 iOS 解析参数会出问题尤其是地址里带查询字符串的时候。这个坑我第一次踩的时候排查了整整一个下午。服务器侧要注意 MIME 类型。.ipa文件的Content-Type建议设成application/octet-stream.plist设成application/xml或application/octet-stream。有些 CDN 会根据自己的推断返回text/html导致下载下来变成了网页。用 Nginx 的话大概是这样location ~* \.ipa$ { default_type application/octet-stream; add_header Content-Disposition attachment; } location ~* \.plist$ { default_type application/xml; }还有个很实际的问题ipa 文件通常几十兆放在普通服务器上多人同时下载容易把带宽打满。有条件的话把 ipa 放到对象存储 CDN 上manifest.plist 和下载页放在应用服务器上这样体验会好很多。5.4 用户在手机上要做的动作完整流程是这样的建议把这段话直接写进给用户的通知里用户在 iPhone 上打开 Safari输入下载页地址或者从消息里长按复制链接到 Safari→ 点击点击安装 → 系统弹出要安装巡检助手吗 → 点安装 → 回到桌面能看到图标变灰、进度圈在转 → 等下载完成 → 第一次点击图标弹出未受信任的企业级开发者 → 打开设置 → 通用 → 往下滑找到设备管理相关的入口不同系统版本这里可能显示为描述文件或描述文件与设备管理→ 找到对应的开发者名称 → 点进去选信任 → 再回桌面打开就能正常用了。这里有两个高频问题。一是用户在微信里点链接页面能打开但点安装按钮毫无反应因为内置浏览器不支持这个协议必须引导用户右上角用 Safari 打开。二是信任这一步如果用户在设置里找不到设备管理入口通常是因为还没有真正点开过 App——必须先在桌面点一次图标、触发那个未受信任的提示设置里的入口才会出现。6. 加固、重签名与热更新的边界包发出去了接下来是维护阶段。这一块遇到的问题往往比首次打包更棘手因为涉及已经装在用户手机上的包。6.1 加固之后为什么必须重新签名很多团队会对 ipa 做加固处理把二进制搞乱、加壳、防反编译。加固工具改的是 Mach-O 可执行文件本身而 iOS 的签名是对整个 App Bundle 做的哈希校验——只要二进制变了原来的签名就失效了。这时候直接安装系统会报无法验证其完整性。解决方案就是重签名用你自己的证书和描述文件重新给这个包签一遍。热词里uni-app 开发的 app 加固后如何重新签名问的就是这件事。原理不复杂但顺序做错就会失败。6.2 codesign 重签名命令拆解完整流程分六步我按顺序写。# 1. 解压原始 ipa unzip -q hardened.ipa -d work cd work # 2. 删掉旧的签名目录 rm -rf Payload/YourApp.app/_CodeSignature # 3. 替换描述文件 cp /path/to/new.mobileprovision Payload/YourApp.app/embedded.mobileprovision # 4. 先签 Frameworks 里的动态库和 Framework顺序很重要 codesign --force --sign iPhone Distribution: Your Company Co., Ltd. \ --timestampnone Payload/YourApp.app/Frameworks/*.framework codesign --force --sign iPhone Distribution: Your Company Co., Ltd. \ --timestampnone Payload/YourApp.app/Frameworks/*.dylib # 5. 再签主 App codesign --force --sign iPhone Distribution: Your Company Co., Ltd. \ --entitlements ent.plist --timestampnone Payload/YourApp.app # 6. 校验并重新打包 codesign --verify --deep --strict --verbose2 Payload/YourApp.app zip -qr resigned.ipa Payload几个必须解释的点。顺序绝对不能反iOS 是嵌套签名主 App 的签名会覆盖内部所有的代码资源如果先签主 App 再签 Framework框架层的签名会被覆盖安装后打开就闪退。--timestampnone在 In-House 场景下建议加上因为时间戳服务器在国内访问经常超时加上这个参数能跳过联网请求签名速度快很多。entitlements文件如果不确定可以从描述文件里提取出来或者干脆不加这个参数——企业证书场景下大部分 entitlements 都是默认值。签名时用的证书名称必须和钥匙串里证书的完整名称一字不差。可以用security find-identity -v -p codesigning列出本机所有可用的签名身份直接从输出里复制。6.3 wgt 热更新在非商店分发下的边界uni-app 的 wgt 热更新是个很实用的能力把前端资源打成一个 wgt 包App 启动时检查版本、下载、调用plus.runtime.install安装用户无感完成更新。内部工具用这个做快速迭代非常爽。但有几个边界要清楚。第一wgt 只能更新前端资源也就是 vue 页面、js、css、静态图片任何涉及原生插件、权限、Info.plist 的改动都不可能通过 wgt 生效必须重新打包发版。第二wgt 安装后需要重启应用才生效虽然plus.runtime.install可以带force参数自动重启但体验上会闪一下要做好版本号提示避免用户以为出 bug 了。第三企业证书分发的场景下做热更新一旦你的 wgt 包出问题用户端会大面积崩溃所以强烈建议做灰度——先让一小部分内部设备更新观察一天没问题再全量。第四也是最容易被忽略的wgt 包本身要校验完整性下载一半中断导致的半成品包安装后会白屏代码里一定要加文件大小和哈希校验。7. 问题排查速查表与踩坑实录前面讲的都是顺利路径但实际项目里出问题的概率不低。这一节把我和身边同行遇到过的典型问题整理出来按现象分类方便对号入座。7.1 安装阶段的报错怎么定位无法安装此 App因为无法验证其完整性。这个报错九成是签名层面的问题按这个顺序查ipa 是否被下载过程中损坏对比一下文件大小和 MD5、描述文件里的证书和 ipa 里的签名证书是否是同一张、ipa 是否经过重签名且重签名不完整。无法安装请稍后重试。这个通常是网络或 plist 层面的问题。先确认 manifest.plist 能不能在浏览器里直接打开再看里面的bundle-identifier和 ipa 实际的 Bundle ID 是否一致。还有一个隐蔽原因如果 ipa 放在 CDN 上某些 CDN 会对超过一定大小的文件做分片或者改写导致 iOS 下载到的包不完整这种情况换一个直链试试。点安装没任何反应。几乎都是因为不在 Safari 里打开的或者在微信内置浏览器里。别怀疑代码先换个浏览器。弹窗一闪而过。一般是 plist 里的 bundle-identifier 写错了或者 plist 文件的 XML 格式有问题比如 BOM 头、缩进里有非法字符。用一个 XML 校验工具过一遍。7.2 装上了但打开就闪退表现在打开瞬间消失没有日志。最常见的原因是描述文件过期或证书被吊销。检查方法是让用户在设置里看那个开发者名称还在不在或者你自己用security cms -D看 ExpirationDate。企业证书被吊销是突发性的所有用户同时失效这也是为什么我一直建议要有 Plan B。用户装在非 Ad Hoc 描述文件里的设备上。Ad Hoc 场景下如果目标设备的 UDID 没被写进描述文件装的时候就会失败但如果描述文件是旧的里面没有这台设备而 ipa 是新的可能表现为装上后立刻退出。核对ProvisionedDevices是唯一可靠的办法。隐私权限描述缺失。前面讲过调用相册、蓝牙、定位但没写描述系统直接杀进程。排查方法是让用户录屏看是在哪个页面崩的然后对照 manifest.json 里的模块勾选把对应的描述补上。重签名不完整。Frameworks 目录下有动态库没被签或者签的顺序错了表现也是打开闪退。用codesign --verify --deep --strict能查出来。7.3 网络、权限与蓝牙的疑难杂症打包后接口请求全部失败。如果你的后端是 HTTP 而不是 HTTPSiOS 的 ATSApp Transport Security会直接拦截。解决方式有两种把后端换成 HTTPS推荐或者在 manifest.json 的 iOS 配置里开启允许 HTTP 明文请求。后一种在打包界面通常有对应的开关不同 HBuilderX 版本位置略有差异找不到就在源码视图里搜ats节点。关于uni-app network: unavailable。这个提示和打包无关它出现在 HBuilderX 真机运行调试的时候通常是手机和电脑不在同一个局域网、或者 HBuilderX 的服务端口被防火墙拦了。别把它和打包后的网络问题混为一谈两者的排查方向完全不同。蓝牙在 iOS 上用 deviceId 建连的坑。这是一个很值得展开的点。CoreBluetooth 在 iOS 上不会给你设备的真实 MAC 地址你拿到的deviceId其实是系统生成的一个 UUID。这个 UUID 在同一台手机、同一个 App 内是相对稳定的但换一个 App 去扫同一台设备拿到的 UUID 完全不同所以不能用它做跨应用的设备唯一标识。另外uni.openBluetoothAdapter之后扫描到的设备列表是动态的缓存 deviceId 时要注意时效性设备重启、系统蓝牙开关重启之后缓存可能失效。稳妥的做法是连接时用 deviceId 优先失败后重新扫描并按设备名称或自定义的服务特征值来匹配。关于uni-app x 怎么使用 renderjs。简短回答是uni-app x 不支持 renderjs它走的是 UTS 编译到原生的路线原来的 renderjs 那套 dom 操作逻辑需要改写。如果你的项目重度依赖 renderjs短期内还是留在 uni-app 上更稳妥。7.4 常见问题速查表现象最可能的原因快速验证方式无法验证完整性签名/证书不匹配或包损坏codesign -dv看 Authority安装无反应非 Safari 打开换 Safari 重试弹窗一闪而过plist 里 bundle-id 错误浏览器直接打开 plist 核对桌面图标白块display-image 404浏览器访问图标地址打开闪退权限类隐私描述缺失对照模块勾选补描述打开闪退签名类描述文件过期或重签不完整security cms -D看 ExpirationDate接口全失败ATS 拦截 HTTP抓包看是否有请求发出多人同时下载失败服务器带宽或 CDN 缓存换直链下载测试版本号显示不对plist 里 bundle-version 未更新改 plist 重新发布加固后装不上未重签名按 6.2 流程重签最后分享一个我在实际维护中总结出来的做法给每一个发出去的包做一份发布记录内容包括版本号、Bundle ID、签名用的证书名、描述文件的过期时间、ipa 的 MD5、下载页地址。这份表平时用不上但等到半年后某个用户反馈装不上了你打开表一查就知道是不是描述文件到期了比翻聊天记录快得多。另外企业证书和 Ad Hoc 描述文件都是一年有效期建议在日历里提前一个月设个提醒到期前把新包发出去别等到用户集体打不开应用的那天再手忙脚乱。
返回列表