This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

fix: stub MLKit Clearcut telemetry to prevent crash (v4.15.2)

Kima crash: -[MLKITx_CCTClearcutLogger log:completion:] background
dispatch → ... → +[MLKITx_CCTClearcutFileUtility
computeUrlForLogContextDir:context:bundleId:] "unrecognized selector".
MLKit's telemetry subsystem is fire-and-forget on an internal dispatch
queue and doesn't surface the crash until deep in the call chain.

Telemetry isn't needed for pose detection. Swizzle the entry-point
`-[MLKITx_CCTClearcutLogger log:completion:]` to a no-op that signals
success via the completion handler, so the failing writeLog → file-IO
path is never reached.

Installation runs twice for robustness: once at +load (may be too early
if MLKit's classes haven't registered yet) and once from
mlkit_set_resource_dir (called from Kotlin after app init, when all
classes are guaranteed loaded). A flag short-circuits if the first
attempt succeeded.

Version bumped to 4.15.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+40 -1
+1 -1
posedetection/build.gradle.kts
··· 4 4 5 5 mavenPublishing { 6 6 publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) 7 - coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.15.1") 7 + coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.15.2") 8 8 9 9 pom { 10 10 name.set("Pose Detection")
+39
posedetection/src/nativeInterop/mlkitRedirect/MLKitResourceRedirect.m
··· 16 16 17 17 static NSString *_mlkitResourceDir = nil; 18 18 19 + // Install the Clearcut-telemetry no-op swizzle. Safe to call multiple times — 20 + // once it actually lands the stub, a flag short-circuits future attempts. 21 + // Runs at two points: during +load (MLKit classes may not be registered yet, 22 + // in which case we silently skip and retry), and from mlkit_set_resource_dir 23 + // (called by Kotlin after app init — all classes definitely loaded by then). 24 + static void _pd_mlkit_noop_log(id, SEL, id, id); 25 + static BOOL _pd_clearcut_stubbed = NO; 26 + static void _pd_install_clearcut_stub(void) { 27 + if (_pd_clearcut_stubbed) return; 28 + Class clearcut = NSClassFromString(@"MLKITx_CCTClearcutLogger"); 29 + if (!clearcut) return; 30 + Method logM = class_getInstanceMethod(clearcut, 31 + @selector(log:completion:)); 32 + if (!logM) return; 33 + method_setImplementation(logM, (IMP)_pd_mlkit_noop_log); 34 + _pd_clearcut_stubbed = YES; 35 + } 36 + 19 37 __attribute__((visibility("default"))) 20 38 void mlkit_set_resource_dir(const char *path) { 21 39 if (path) { ··· 23 41 } else { 24 42 _mlkitResourceDir = nil; 25 43 } 44 + _pd_install_clearcut_stub(); 26 45 } 27 46 28 47 static NSSet<NSString *> *mlkitBundleNames(void) { ··· 38 57 return names; 39 58 } 40 59 60 + // No-op replacement for -[MLKITx_CCTClearcutLogger log:completion:]. 61 + // MLKit's Clearcut telemetry subsystem crashes at runtime on some iOS 62 + // versions when it tries to compute a log-context URL (the selector 63 + // `+[MLKITx_CCTClearcutFileUtility computeUrlForLogContextDir:context:bundleId:]` 64 + // goes missing at the app-link step even with -ObjC when the consumer 65 + // builds a static framework). Telemetry isn't needed for pose detection, 66 + // so we replace the top-level log entry with a completion-handler call 67 + // that signals success but does nothing. 68 + static void _pd_mlkit_noop_log(id self, SEL _cmd, id event, id completion) { 69 + if (completion) { 70 + void (^block)(BOOL, NSError *) = completion; 71 + block(YES, nil); 72 + } 73 + } 74 + 41 75 @interface NSBundle (PoseDetectionMLKitRedirect) 42 76 @end 43 77 ··· 51 85 Method newM = class_getInstanceMethod(self, 52 86 @selector(pd_mlkit_URLForResource:withExtension:)); 53 87 method_exchangeImplementations(origM, newM); 88 + 89 + // Try to install the Clearcut no-op now; if the class isn't 90 + // registered yet (MLKit loaded after us), this is a silent no-op 91 + // and mlkit_set_resource_dir re-attempts later. 92 + _pd_install_clearcut_stub(); 54 93 }); 55 94 } 56 95