Add Find My Friends helper for newer macOS - #65
Conversation
qayshp
left a comment
There was a problem hiding this comment.
Maintainer review: this demonstrates the macOS 16 Friends path, but it needs production hardening before merge. Remove machine-local build settings and opaque framework descriptions from the wire format, make timeout responses complete and explicitly partial when necessary, and provide a repeatable universal artifact build. Please add serializer/transaction tests covering a nil handle, no location, cached location, live location, and refresh timeout.
|
FYI @zlshames If instead of looking at cache decryption as in BlueBubblesApp/bluebubbles-server#810, I have this work-in-progress branch and PR adding Find My support on newer Mac OS to the Private API.
BlueBubblesApp/bluebubbles-server#810 (comment) While it is working and I am using it locally, it is not up to par for wider use yet. |
I was testing it, but I think we are going to go the papi route instead. There's a lot more setup and gotchas to account for with the cache decryption method |
qayshp
left a comment
There was a problem hiding this comment.
Second maintainer-style pass on c0114f6: I do not see a remaining blocking finding in the updated diff.
The earlier concerns are addressed: machine-local build settings and copied private headers are gone; the private API surface is limited to selectors this helper uses; payloads are explicitly allowlisted; nil locations and unidentifiable records are handled without exporting opaque descriptions; timeout responses are deterministic and explicitly partial; and the build produces and verifies an x86_64/arm64 artifact with the expected install name.
I reran the payload tests and universal build after the cleanup. I also validated this exact helper through the companion packaged server: Find My loaded the dylib from that app bundle, and the Friends refresh returned 8 records, 5 with coordinates and 3 without a current location.
Non-blocking test gap: the payload/partial metadata is tested, but the asynchronous coordinator itself is still covered by live validation rather than a fake FindMyLocateSession. Before calling this fully regression-proof, I would add tests for friend-list timeout fallback, per-handle timeout, duplicate or late completion callbacks, and reconnect during an in-flight refresh.
qayshp
left a comment
There was a problem hiding this comment.
Final maintainer pass on 324b757c: the asynchronous coverage gap from my previous review is now closed.
The refresh orchestration is isolated behind a fakeable session protocol and tested for friend-list fallback, per-handle deadlines, duplicate and late completions, deterministic partial responses, reconnect queue ordering, and stale socket callbacks. During live validation, the first extraction exposed a real private-framework contract issue: a friend wrapper also answered identifier, but Swift required the nested FMLHandle. The implementation now performs strict FMLHandle selection when that class is available, and the test fixture reproduces that shape so the crash cannot regress silently.
The helper tests and universal build pass. The exact rebuilt dylib was then packaged, loaded into Find My, reconnected after a controlled Find My restart, and returned 8 Friends records through the Android-facing route, including 5 with coordinates and 3 without. Final logs contain no Swift array element cast, timeout, framing, or transaction error.
I do not see another helper change needed before merge.
qayshp
left a comment
There was a problem hiding this comment.
Final maintainer-style pass after synchronizing with upstream/master:
Commit e916e83 removes project cruft that would make this harder to review: unused AppKit/private-framework links, duplicate socket references, nonexistent Swift settings, empty phases, workspace metadata, and an unused prefix-header resource. Runtime private-framework loading remains explicit in the helper, and the vendored CocoaAsyncSocket dependency remains because it is compiled and matches the repository's existing dependency layout.
The first-party helper has no static-analyzer diagnostics. Unit tests and the universal x86_64/arm64 build pass, the install name is correct, and the exact artifact was loaded by Find My from the packaged server app. Live GET/refresh/GET returned HTTP 200 with all 8 Friends records and no private/debug fields.
I do not see another actionable code or project-configuration finding before maintainer review. Remaining analyzer/whitespace diagnostics are confined to the untouched vendored CocoaAsyncSocket sources.
Summary
com.apple.findmyhelper for Friends on macOS 15 and laterFindMyLocateObjCWrapperto enumerate friends and refresh locationsBehavior
A refresh coordinator seeds every friend from the current Find My cache, then requests an updated location. Slow refreshes do not remove friends from the response. Friend-list and per-handle deadlines resolve once, ignore duplicate or late callbacks, and report timed-out or unidentifiable records explicitly.
Private-framework descriptions are never serialized. Payloads contain only named handle, coordinate, address, timestamp, status, and accuracy fields. Friend wrapper objects are resolved to the underlying
FMLHandlebefore calling private-framework methods.Project cleanup
Building does not install into
/Applications, terminate Find My, or modify a BlueBubbles installation.Validation
./FindMy/MacOS-15+/Tests/run-tests.shpasses./FindMy/MacOS-15+/scripts/build-universal.shpasses forx86_64andarm64@rpath/BlueBubblesFindMyHelper.dylib99e5e9596c0c095f08f5083353053d77fbf458e54727f8160dabe3873c4fa39aCompanion server PR: BlueBubblesApp/bluebubbles-server#824