Android 13/14/15 compatibility + native build restore (v2.0.5) - #66
Conversation
- Re-enable externalNativeBuild and pin ndkVersion 26.1.10909125
- Fix CMake include path to ${CMAKE_CURRENT_SOURCE_DIR} and add project()
- Fail fast on release builds when signing env vars are missing instead of
silently producing a debug-signed (non-upgradeable) artifact
- Stop tracking stale in-tree CMake build artifacts; ignore them via jni/.gitignore
- Bump versionPatch 4 -> 5 (2.0.5)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit the abp-filter-parser-cpp / tracking-protection / hashset-cpp / bloom-filter-cpp C++ sources directly in-tree (previously pulled via npm postinstall, which was removed). externalNativeBuild references these, so a clean checkout could not build without them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…TIFICATIONS flow - Start MainService via ContextCompat.startForegroundService and attach the notification channel on O+; stopForeground correctly in onDestroy - Replace leftover 'snap map' channel name/id with a proper app channel constant - Null-guard MainController.get() in the screen/config/close-dialog receivers to avoid NPE crashes when the controller is gone - Use PackageInfoCompat.getLongVersionCode for API 28+ WebView version lookup - Runtime POST_NOTIFICATIONS request flow on Tiramisu+ (rationale + denied toast) - Sync AndroidManifest template with FOREGROUND_SERVICE perms + specialUse type - Fix self-assignment bug (int targetX = targetX = ...) in BubbleDraggable Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Refresh repo/module .gitignore entries - Drop runtime dependencies / postinstall from package.json (JNI sources now vendored in-tree) and refresh package-lock Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README: native sources are vendored in-tree, no postinstall step - Update AGENTS.md / GEMINI.md / project-handbook and Android 15 review notes - Add WORKLOG.md, Windows.md and node-dependency-findings notes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…te/docs sync Addresses local 3-pass review (codex) findings: - Only pass FOREGROUND_SERVICE_TYPE_SPECIAL_USE on API 34+ (it does not exist on API 29-33 and would crash startForeground there); 2-arg call below - Register internal system-broadcast receivers as RECEIVER_NOT_EXPORTED so other apps cannot spoof them - Sync manifest template with the real manifest: add <queries> for Android 11+ package visibility and the specialUse FGS subtype <property> - README: list LINK_BUBBLE_KEY_ALIAS (required by release fail-fast) and drop stale 'native module failure' Node warnings Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…just HomeActivity Link Bubble's primary entry point (EntryActivity) opens links and finishes without ever showing HomeActivity, so the runtime POST_NOTIFICATIONS request added there never fired for the most common usage, leaving the foreground service notification suppressed on Android 13+. MainService now triggers the request on startup (covering every entry path) via a new transparent NotificationPermissionActivity, guarded so it asks at most once per service lifetime. Registered in both the manifest and its template. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep AndroidManifest.xml in sync with its template (the property was only added to the template in the previous commit). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The MainService trigger relies on a background activity launch, which Android 10+ can block once EntryActivity has finished and no window is visible. Since EntryActivity is still the foreground activity at the point it starts the bubble service, initiate the request from here (delegating to NotificationPermissionActivity) so the dialog is reliable on the primary entry path; the service trigger remains as a fallback for other paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rvice permission launch gemini-grade-review round 1 (verified findings): - build.gradle: isRelease matched any task name containing 'Release', so the new fail-fast aborted lint*/test*Release tasks (and thus the whole configuration) when signing env vars were absent. Scope it to assemble/bundle *Release only, and add a taskGraph warning when a plain build/assemble would debug-sign the release variant (instead of failing those non-release workflows). - MainService.maybeRequestNotificationPermission: a Service can't launch an activity from the background (an active FGS is still 'background' for BAL), so only burn the 'requested' flag once startActivity is actually accepted, letting a later foreground-triggered start retry. EntryActivity/HomeActivity remain the reliable request paths; this is a documented best-effort fallback. (Refuted this round: FGS 5s-timeout crash — onCreate() already calls startForeground() via showDefaultNotification(); double permission dialog — NotificationPermissionActivity is singleInstance and does not re-request.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gemini-grade-review round 1 (B1, high): 344 files under Application/LinkBubble/.externalNativeBuild/ (CMakeCache.txt, per-ABI CMakeFiles, .o/.a build products, host-absolute-path caches) were tracked in master. The existing ignore rule (Application/.gitignore) only blocks new additions and cannot untrack already-committed files, so a fresh clone still shipped hundreds of stale, toolchain-specific binaries — the same class of problem this branch's native-build cleanup set out to fix. Remove them from the index (files stay on disk; regenerated by CMake) and add a local /.externalNativeBuild rule alongside /build and /.cxx for robustness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rmission prompt
gemini-grade-review round 2 (verified findings):
- build.gradle: the fail-fast used a case-sensitive contains("Release") on raw CLI
task names, so `./gradlew assembleplaystorerelease` (Gradle resolves task names
case-insensitively) bypassed it. Move the guard into taskGraph.whenReady keyed on
*resolved* task names; hard-fail an explicit release packaging task without
signing, warn when a plain build/assemble would incidentally build it. Paired with
leaving the release variant UNSIGNED (not debug-signed) when secrets are absent, so
an unshippable artifact is the worst case.
- Notification permission: the 'already asked' state was a per-instance/per-process
flag, so HomeActivity re-popped the rationale dialog on every recreation (rotation,
revisits) after a denial. Replace it with a persisted (SharedPreferences) flag via
shared NotificationPermissionActivity.shouldAutoRequest()/markAsked() helpers used
by EntryActivity, HomeActivity and MainService, so the prompt fires at most once
per install. Removes the duplicated per-caller checks and now-unused imports.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ale findings gemini-grade-review round 3 (documentation findings; code review was clean): - GEMINI.md: an incomplete section-2 extraction left leftover temp_ops.py commands with no opening fence, a dangling closing fence, and an orphaned "### 2.5 ADB" subsection with no parent heading. Remove the leftovers; the Windows-only content now lives solely in Windows.md. - Windows.md: the file ended on an unclosed bash fence (odd fence count). Add the missing temp_ops.py example commands + closing fence, and fold in the ADB note. - AGENTS.md / GEMINI.md: the "PR Review 自動化循環" step 3/4 were copy-pasted from an unrelated Python project (ruff/mypy/pytest, src/autonomous_agent, a "homee" remote that does not exist here). Replace with this repo's real checks (npm run lint + gradlew assembleDebug) and push to origin only. - docs/node-dependency-findings.md: mark superseded — this PR already vendored the JNI sources and dropped the postinstall/native-dep chain the doc treated as current and listed as a future step. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d state gemini-grade-review round 4 (Codex cross-check; code review was clean on both the Opus tracer and Codex passes): - docs/android15-compatibility-review.md: sections 1-3 still framed already-implemented work (notification-permission flow, FOREGROUND_SERVICE perms, startForegroundService) as future remediation TODOs, which reads as if the main fix were missing. Rewrite each "Remediation plan" into a "Status — done / Remaining (validation only)" that matches what this PR actually implements. - README.md: the "Update SDK version" note still said to set compile/target to 33 and min to 28; the project is on compile/target 34, min 21. Correct it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 360 files, which is 210 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (63)
📒 Files selected for processing (360)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
/gemini review |
4 similar comments
|
/gemini review |
|
/gemini review |
|
/gemini review |
|
/gemini review |
What
Restores the native (ad-block / tracking-protection) build and brings Link Bubble into
compliance with Android 13/14/15 foreground-service and runtime-permission rules, then
bumps the version to 2.0.5.
Changes
Android 13/14/15 compatibility
foregroundServiceType="specialUse";startForegroundpasses theSPECIAL_USEtype only on API 34+ (UPSIDE_DOWN_CAKE) — passing it on API 29–33 would crash.stopForegroundhandled correctly in
onDestroy.POST_NOTIFICATIONSruntime-permission flow: a transparentNotificationPermissionActivityrequests the permission, triggered from the visible entry points (
EntryActivityfor theopen/share path and
HomeActivity), withMainServiceas a best-effort fallback. The promptis backed by a persisted flag so it fires at most once per install instead of nagging on
every recreation.
BroadcastReceivers (screen / config-changed / close-system-dialogs) registeredRECEIVER_NOT_EXPORTED.ContextCompat.startForegroundService,PackageInfoCompat.getLongVersionCode, and null-guardsaround
MainController.get()in the receivers.Native build
externalNativeBuild/ CMake and pinnedndkVersion.Application/LinkBubble/src/main/jni/(previouslypulled via an npm
postinstall, now removed), so a clean checkout builds. Stopped trackingin-tree CMake /
.externalNativeBuildbuild artifacts.Release signing
based, so CLI casing can't bypass it); a plain
build/assemblewarns instead. When secretsare absent the release variant is left unsigned (unshippable) rather than debug-signed.
Housekeeping
AndroidManifest.xmlwith its.template(permissions,<queries>,foregroundServiceType,PROPERTY_SPECIAL_USE_FGS_SUBTYPE, activity registration).google-services.json(contains a Firebase key) added to.gitignore— not committed.2.0.4→2.0.5. Documentation cleanup.Testing
./gradlew :LinkBubble:assembleDebugbuilds green (native compiled for all ABIs). Debug variantis
.dev-suffixed, so it installs alongside a real build.gemini-grade-reviewfix-loop to convergence — 5 rounds, the final pass clean across four independent code reviewers.
tracked in
docs/android15-compatibility-review.md.🤖 Generated with Claude Code