❌

普通视图

发现新文章,点击刷新页面。
昨天以前首页

技术依赖

作者 obaby
2026年10月19日 14:47

今天早上收到uniapp云空间续费的通知,看了下还有一个月到期,点击续费的时候发现最长时间选不到一年了。

看了半天才注意到底下那张字:

因阿里云 EMAS 功能逐步下线,uniCloud阿里云服务空间自2026年11月1日起不再支持新建,并将于2027年9月30日正式停服,续费后的到期时间不得晚于2027年8月31日,建议您尽快迁移,

一句话总结,就是阿里云的空间续费不了了,只能换其他的。甚至还贴心的给出了迁移工具,

这个东西聊胜于无,有总比没有要好一些。然而,及时是如此还得面临一系列的问题,域名不能同时存在,如果要想业务不中断就得先发布版本替换线上使用的域名,切换到新域名。无形中增加了app和服务的运维成本。

后面几个app的推送也用的unicloud的云空间,不过这次没有再使用uniadmin之类的面板也没有再为每个app创建独立的云空间。将多个app绑定到了同一个空间,毕竟这些app使用的功能也只有消息推送而已,完全没必要每个再创建一个独立的空间。毕竟dcloud提供一个免费的空间,剩下的都得花钱购买了,免费的先用着也不是不可。

新空间是支付宝云,倒是不受这次迁移的影响。这一切的原因都是因为选择了uni的框架,鉴于所谓的省时省力使用了uni的管理后台和推送服务,这包装好的一切虽然前期省了时间,如果没什么变数长期运维整体成本感觉也还可以。只是一点有了变数之后,所有的一切不说是推到重来,实际上跟挖了重载也差不多了。

之所以说这件事情,还有一件事情,上周五有个哥哥加qq问findu 是不是收费,能不能下载新版本。

其实,上来就说app闪退就可以了。来回折腾了半天我才直到是闪退,问了下手机版本 iPhone 15 pro, iOS27。自己的手机前几天也升级到了27,但是并没有闪退,虽然我猜测可能是ios版本问题,但是鉴于自己的手机没闪退,又猜测是不是硬件问题。

好在最后哥哥在自己的一通指挥下成功的把app崩溃日志发给了自己:设置 → 隐私与安全性 → 分析与改进 → 分析数据‌,在里面找到对应 App 的 .ips 文件(命名一般是 App名-日期-时间.ips

看到这一堆文件,心理瞬间没那么慌了,毕竟有了文件,就知道是崩在哪里了。

系统断言:

You cannot set a delegate on the default file manager.

符号化后的调用链:


-[NSFileManager setDelegate:]
-[PDRCoreApp copyOverlayFile]          ← DCloud 引擎
-[PDRCoreApp load]
+[PDRCore initEngineWihtOptions:...]
-[AppDelegate didFinishLaunching...]
也就是说:iOS 27 禁止给 NSFileManager.defaultManager 设 delegate,而 DCloud 离线 SDK 启动复制 www 资源时还在这么做,所以一进启动页就 EXC_BREAKPOINT 秒退。崩溃二进制 UUID 与 10/8 的 4.0.5 Archive 一致。

这个问题,其实在上次兼容适配iphone duo的时候修复过一次了,不过那次是在家里的mac mini上操作的,而mbp的xcode 不知道什么时候也升级到27了,这就导致打出来的包使用了ios 27的sdk,就直接引入了这个bug。

当然,更诡异的是自己从26升级到27的系统上,之前安装的findu并没有闪退,卸载重装就是就闪退了。

这个东西的原因后来也想明白了(后知后觉,今天才想明白),在ios26上已经完成文件复制了,所以系统升级之后,并不会再次触发文件复制。而新装的app在启动的时候会复制文件就bug了。

所以,如果uniapp 离线打包ios27闪退,那就直接修改离线工程的代码吧xcode_project/Findu/Findu/NSFileManager+Findu.m(+load swizzle):

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <string.h>

// iOS 27 SDK 起,Foundation 会在 -[NSFileManager setDelegate:] 作用于
// defaultManager 且 delegate 非空时主动陷阱(EXC_BREAKPOINT)。
// DCloud PDRCoreApp copyOverlayFile 启动时仍靠这个委托把 www 合并进沙盒,
// 会在启动页秒退。兄弟项目 dayima 已验证本补丁。
//
// 非共享的 NSFileManager 不会陷阱。先在临时实例上走系统实现,
// 再把 _delegate / _weakDelegateValue 挪到 defaultManager 上。
// _delegate 是 assign。_weakDelegateValue 必须强持有:
// object_setIvar 对未知所有权按 unsafe_unretained 写入,临时实例释放后
// NSWeakObjectValue 被回收,后续文件操作会打到野指针。
static IMP findu_originalSetDelegate;

static void findu_nsfilemanager_setDelegate(id self, SEL _cmd, id delegate) {
    if (delegate != nil && self == [NSFileManager defaultManager]) {
        NSFileManager *donor = [[NSFileManager alloc] init];
        ((void (*)(id, SEL, id))findu_originalSetDelegate)(donor, _cmd, delegate);
        Ivar delegateIvar = class_getInstanceVariable([NSFileManager class], "_delegate");
        Ivar weakIvar = class_getInstanceVariable([NSFileManager class], "_weakDelegateValue");
        if (delegateIvar != NULL) {
            void *rawDelegate = (__bridge void *)delegate;
            void *slot = (char *)(__bridge void *)self + ivar_getOffset(delegateIvar);
            memcpy(slot, &rawDelegate, sizeof(rawDelegate));
        }
        if (weakIvar != NULL) {
            object_setIvarWithStrongDefault(self, weakIvar, object_getIvar(donor, weakIvar));
        }
        return;
    }
    ((void (*)(id, SEL, id))findu_originalSetDelegate)(self, _cmd, delegate);
}

@interface NSFileManager (Findu)
@end

@implementation NSFileManager (Findu)

+ (void)load {
    Method method = class_getInstanceMethod(self, @selector(setDelegate:));
    if (method == NULL) {
        return;
    }
    findu_originalSetDelegate = method_getImplementation(method);
    method_setImplementation(method, (IMP)findu_nsfilemanager_setDelegate);
}

@end

以前做的东西,并没有很多与硬件交互的内容,所以uni 『从从容容游刃有余』,现在随着对接apple watch 以及carplay,uni变得越来越『匆匆忙忙连滚带爬』了。

毕竟,启动闪退这种bug对于任何app来说都是无法忍受的。好在这次苹果的审核还是非常不错的,提交之后第二天就通过了。

这一桩桩一件件,怎么想都是事儿。只是,真的要推倒重来,真的太需要勇气了。毕竟,已经修复了无数的问题。

所以,做产品,如果要长期做,宜长远考虑。

❌
❌