RepoPilotOpen in app →

tbruyelle/RxPermissions

Android runtime permissions powered by RxJava2

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 19 active contributors
  • Apache-2.0 licensed
  • CI configured
Show all 6 evidence items →
  • Tests present
  • Stale — last commit 4y ago
  • Concentrated ownership — top contributor handles 59% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tbruyelle/rxpermissions)](https://repopilot.app/r/tbruyelle/rxpermissions)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tbruyelle/rxpermissions on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tbruyelle/RxPermissions

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tbruyelle/RxPermissions shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 19 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 4y ago
  • ⚠ Concentrated ownership — top contributor handles 59% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tbruyelle/RxPermissions repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tbruyelle/RxPermissions.

What it runs against: a local clone of tbruyelle/RxPermissions — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tbruyelle/RxPermissions | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 1488 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tbruyelle/RxPermissions</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tbruyelle/RxPermissions. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tbruyelle/RxPermissions.git
#   cd RxPermissions
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tbruyelle/RxPermissions and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tbruyelle/RxPermissions(\\.git)?\\b" \\
  && ok "origin remote is tbruyelle/RxPermissions" \\
  || miss "origin remote is not tbruyelle/RxPermissions (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java" \\
  && ok "lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java" \\
  || miss "missing critical file: lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java"
test -f "lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissionsFragment.java" \\
  && ok "lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissionsFragment.java" \\
  || miss "missing critical file: lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissionsFragment.java"
test -f "lib/src/main/java/com/tbruyelle/rxpermissions3/Permission.java" \\
  && ok "lib/src/main/java/com/tbruyelle/rxpermissions3/Permission.java" \\
  || miss "missing critical file: lib/src/main/java/com/tbruyelle/rxpermissions3/Permission.java"
test -f "lib/build.gradle" \\
  && ok "lib/build.gradle" \\
  || miss "missing critical file: lib/build.gradle"
test -f "sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java" \\
  && ok "sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java" \\
  || miss "missing critical file: sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1488 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1458d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tbruyelle/RxPermissions"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

RxPermissions is a lightweight RxJava2/3 wrapper that simplifies Android runtime permission requests (Android M+) by exposing them as reactive observables. Instead of implementing callbacks via FragmentManager, developers compose permission checks into RxJava streams with single .request() or .requestEach() calls, seamlessly integrating with existing Rx code. Standard Android library structure: lib/src/main/java/com/tbruyelle/rxpermissions3/ contains the core logic (RxPermissions.java, RxPermissionsFragment.java, Permission.java), lib/src/test/ holds unit tests, and sample/src/main/ provides a runnable example app. Build uses Gradle with Bintray/JitPack publishing configs.

👥Who it's for

Android developers building apps targeting API 14+ who want to handle runtime permissions reactively without boilerplate FragmentManager callbacks. Particularly valuable for teams already using RxJava2/3 in their architecture and wanting permissions to flow through observable chains.

🌱Maturity & risk

Actively maintained but moderately mature. Version 0.9.5 released with TravisCI integration, comprehensive tests in lib/src/test/java/com/tbruyelle/rxpermissions3/RxPermissionsTest.java, and solid documentation. However, this is a single-maintainer library (tbruyelle) with limited recent activity visible—suitable for production but not high-velocity.

Low-to-moderate risk. Minimal dependencies (only RxJava 3.0.4, AndroidX Fragment 1.2.5, and annotations), reducing supply chain exposure. Single maintainer (tbruyelle) is a fragility point. The library relies on FragmentManager internals for permission request delegation, which could break on major Android API changes, though the small surface area mitigates this.

Active areas of work

Limited visibility into current work from the file structure provided. The repo uses TravisCI (.travis.yml) and is published to JitPack, suggesting maintenance for CI/CD. No active PR branch or changelog snippet is visible, indicating stable maintenance rather than active feature development.

🚀Get running

git clone https://github.com/tbruyelle/RxPermissions.git
cd RxPermissions
./gradlew build
./gradlew :sample:assembleDebug  # Build the sample app

Daily commands: The library is not a runnable app—it's a library dependency. To test locally: ./gradlew :lib:build compiles the library; ./gradlew :lib:test runs unit tests; ./gradlew :sample:assembleDebug builds the sample app APK for manual testing on an emulator/device.

🗺️Map of the codebase

  • lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java — Core entry point that orchestrates permission requests via RxJava2, exposes the public API that all users interact with
  • lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissionsFragment.java — Invisible Fragment that handles Android permission callbacks and lifecycle management, required for request/response plumbing
  • lib/src/main/java/com/tbruyelle/rxpermissions3/Permission.java — Data model representing a single permission grant state, the fundamental unit flowing through RxJava streams
  • lib/build.gradle — Library build configuration specifying RxJava3 and AndroidX dependencies, critical for understanding version constraints
  • sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java — Reference implementation demonstrating the canonical usage pattern for RxPermissions in an Activity

🧩Components & responsibilities

  • RxPermissions (RxJava3 Observable, AndroidX Fragment) — Main API facade that accepts an Activity/Fragment, exposes request() and requestEach() methods, and manages the invisible Fragment lifecycle
    • Failure mode: If Fragment detachment fails or Fragment context is garbage-collected, pending permission requests may hang or emit errors
  • RxPermissionsFragment (Android Fragment, Activity.requestPermissions()) — Retained Fragment that intercepts onRequestPermissionsResult() callbacks from Android OS and converts them into Observable emissions
    • Failure mode: If activity is destroyed before onRequestPermissionsResult() is called, the callback may be lost or arrive on a dead context
  • Permission (Java POJO) — Immutable data model holding a permission name and grant status, emitted through the Observable stream
    • Failure mode: No failure mode; used as data carrier
  • AndroidX Fragment & AppCompat (AndroidX library) — Provides Fragment lifecycle, FragmentActivity support, and ContextCompat.checkSelfPermission() for backwards compatibility
    • Failure mode: If app targets SDK < 14 or uses old Support Library instead of AndroidX, compilation or runtime crashes may occur

🔀Data flow

  • Activity/FragmentRxPermissions constructor — Developer passes Activity or Fragment instance to create RxPermissions, which attaches an invisible Fragment
  • RxPermissions.request()RxPermissionsFragment.requestPermissions() — Request call triggers Fragment to invoke Activity.requestPermissions() with the permission string array
  • Android OSundefined — undefined

🛠️How to make changes

Request a new permission in your Activity/Fragment

  1. Instantiate RxPermissions with 'this' (Activity or Fragment instance) (sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java)
  2. Call rxPermissions.request() with permission string(s) and subscribe to the Observable<Permission> (sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java)
  3. In onNext(), check Permission.granted to determine if user granted or denied the permission (lib/src/main/java/com/tbruyelle/rxpermissions3/Permission.java)

Add a new permission request to the sample app

  1. Add the permission string to the sample app's AndroidManifest.xml <uses-permission> tag (sample/src/main/AndroidManifest.xml)
  2. In MainActivity.java, call rxPermissions.request("android.permission.NEW_PERMISSION") (sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java)
  3. Update the UI to handle the Permission result in the subscription chain (sample/src/main/res/layout/act_main.xml)

Extend RxPermissions for custom permission handling

  1. Subclass RxPermissions or wrap it to add pre/post request logic in your Activity/Fragment (lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java)
  2. Override request() or requestEach() to inject additional Observable transformations or logging (lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissions.java)
  3. Ensure RxPermissionsFragment is still attached for lifecycle callback handling to work (lib/src/main/java/com/tbruyelle/rxpermissions3/RxPermissionsFragment.java)

🔧Why these technologies

  • RxJava 3 — Provides reactive composition for asynchronous permission request/grant workflows; allows chaining multiple permission requests and UI responses declaratively
  • Android Fragment (retained) — Survives configuration changes (rotation) and persists lifecycle state, essential for handling onRequestPermissionsResult() callbacks independently of Activity lifecycle
  • AndroidX libraries — Modern Android framework baseline ensuring compatibility with recent Android OS versions and best practices
  • Gradle build system — Standard Android multi-module build setup, separating the library (lib) from sample app (sample) for clean distribution

⚖️Trade-offs already made

  • Use a retained Fragment rather than a custom PermissionManager Service

    • Why: Fragment lifecycle is tightly integrated with Activity/Fragment contexts, making it simpler to manage requestPermissions() calls
    • Consequence: RxPermissions instance must receive an Activity or Fragment; cannot be used from standalone components without a Fragment context
  • Expose Observable<Permission> rather than Observable<Boolean>

    • Why: Permission object carries both the permission name and grant state, allowing subscribers to know which permission was processed and its result
    • Consequence: Slightly more boilerplate for simple true/false checks, but more composable for multi-permission workflows
  • Attach an invisible Fragment to manage callbacks

    • Why: Decouples permission handling from the main Activity/Fragment logic and survives configuration changes
    • Consequence: Adds a Fragment to the stack; developers must pass the correct Activity/Fragment reference to RxPermissions constructor

🚫Non-goals (don't propose these)

  • Does not handle notification permissions (Android 13+) with a dedicated API; uses standard runtime permission model
  • Does not provide background permission scoping or exemption handling; relies on Android OS enforcement
  • Does not cache or persist permission grants; always queries current OS state
  • Does not offer a suspend/coroutine API; RxJava2 Observable-only

🪤Traps & gotchas

Ensure you pass an Activity or Fragment instance to new RxPermissions(this), not an Activity fetched from Fragment.getActivity()—the README warns this causes 'java.lang.IllegalStateException: FragmentManager is already executing transactions'. The library relies on a headless Fragment managed internally; if you try to manually manage the fragment or use incompatible FragmentManager transactions, permission requests may deadlock. ProGuard rules are defined in lib/proguard-rules.pro—respect them in release builds or reflection-based permission name lookups may break.

🏗️Architecture

💡Concepts to learn

  • Reactive Permissions Bridging — RxPermissions solves the impedance mismatch between callback-based Android permission APIs and reactive Observable streams—a core pattern for integrating system APIs into Rx codebases.
  • Headless Fragment Pattern — RxPermissionsFragment is a headless (no UI) Fragment retained to survive configuration changes and intercept lifecycle callbacks; understanding this pattern is critical to avoiding FragmentManager deadlocks.
  • Subject-based Backpressure Handling — RxPermissions likely uses RxJava Subjects internally to relay FragmentManager callbacks to multiple subscribers; understanding subjects, replay policies, and subscriber lifecycle avoids leaks.
  • Android Runtime Permissions Model (M+) — RxPermissions exists to simplify the Android 6.0+ (API 23+) runtime permission request/grant flow via ActivityCompat.requestPermissions() and onRequestPermissionsResult().
  • Observable Composition & Operators — The library's power comes from composing permission observables with .compose(), .flatMap(), and other operators; mastering RxJava operator chains is essential for advanced usage.
  • Configuration Change Resilience — Permission requests can span activity rotations/configuration changes; RxPermissionsFragment uses Fragment retention to maintain observable continuity across these events.
  • permissions4m/permissions4m — Earlier generation Android permission wrapper without Rx; represents pre-RxJava solution to the same problem.
  • JakeWharton/RxBinding — Complementary RxJava binding library for Android UI events; the README shows composition with RxView.clicks() for event-driven permission requests.
  • ReactiveX/RxJava — Core dependency (RxJava 3.0.4); understanding Observables, operators, and subscriptions is essential to using RxPermissions effectively.
  • androidx/androidx — RxPermissions depends on androidx.fragment and androidx.annotation; staying aligned with AndroidX versions is critical for compatibility.
  • tbruyelle/RxPermissions2 — Historical predecessor branch targeting RxJava2; useful reference for migration patterns or RxJava2-specific projects.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add unit tests for RxPermissionsFragment.java

The repo has RxPermissionsTest.java but it only tests the main RxPermissions class. RxPermissionsFragment.java is a critical component that handles fragment lifecycle and permission request callbacks, but has zero test coverage. This is especially important since fragment lifecycle bugs are common and hard to debug.

  • [ ] Create lib/src/test/java/com/tbruyelle/rxpermissions3/RxPermissionsFragmentTest.java
  • [ ] Add tests for fragment lifecycle callbacks (onCreate, onRequestPermissionsResult)
  • [ ] Add tests for permission request handling with various Android API levels
  • [ ] Use Robolectric (already in dependencies) to mock fragment and activity contexts
  • [ ] Test edge cases like fragment detachment and permission denial scenarios

Add GitHub Actions CI workflow to replace Travis CI

The repo uses .travis.yml (older CI) but Travis CI has deprecated free tier for new repos. GitHub Actions is now standard for GitHub projects. The existing .travis.yml shows the build process, but no GitHub Actions workflow file (.github/workflows/*.yml) exists. This improves maintainability and provides faster feedback to contributors.

  • [ ] Create .github/workflows/android-ci.yml for the main build pipeline
  • [ ] Configure matrix builds for minSdkVersion=14 and compileSdkVersion=29 as specified in gradle.properties
  • [ ] Add steps to run ./gradlew build, lib:test, and sample tests
  • [ ] Add artifact upload for test reports and APK generation
  • [ ] Consider adding dependency caching for gradle wrapper to speed up builds

Add integration tests for Permission.java data class

Permission.java is a core data class returned by the library but there are no tests validating its behavior in real-world scenarios (equality, serialization, state transitions). The sample app in sample/src/main/java/com/tbruyelle/rxpermissions3/sample/MainActivity.java shows actual usage patterns that should be tested.

  • [ ] Create lib/src/test/java/com/tbruyelle/rxpermissions3/PermissionTest.java
  • [ ] Add tests for Permission equality and hashCode contracts (important for collections)
  • [ ] Add tests for granted/denied state transitions
  • [ ] Test Permission behavior when used with RxJava operators (map, filter, etc.)
  • [ ] Add tests matching the observable patterns shown in sample/src/main/java/.../MainActivity.java

🌿Good first issues

  • Add test coverage for edge cases in Permission.java (null name handling, permission caching across multiple rapid requests) in RxPermissionsTest.java.
  • Expand the sample MainActivity.java to demonstrate .requestEach() with detailed per-permission UI feedback and shouldShowRequestRationale() conditional prompts.
  • Document the Fragment lifecycle contract more explicitly in RxPermissionsFragment.java—currently unclear what happens if the Fragment is destroyed mid-request; add tests validating graceful error emission.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • fd2b50f — fix: request permission twice, in one subscribe receive callback twice #344 (#345) (o0starshine0o)
  • cc45207 — Version up (tbruyelle)
  • 405050e — feat: Migrate to RxJava 3 and RxBinding 4 (#326) (galuszkak)
  • 2d1a4d8 — Version up (tbruyelle)
  • 3d4648e — feat: Migrate to Jetpack (AndroidX) (#325) (galuszkak)
  • 234e6db — Add 'Issue template' and 'Bug report template' (#314) (tbruyelle)
  • f6e5637 — change 'Activity' to 'FragmentActivity' (#269) (takecare)
  • ba210b4 — Add Jitpack and Nuget badges (epool)
  • c9b8170 — Fix IllegalStateException and add support for fragments. (#236) (epool)
  • a7c81c3 — Fix unit tests after last changes. (#234) (epool)

🔒Security observations

The RxPermissions library has a moderate security posture with significant concerns around outdated dependencies. The primary risks stem from using Android Gradle Plugin 4.0.0 (3+ years old), outdated AndroidX libraries, and older versions of testing frameworks. While the codebase itself appears to be a straightforward permissions wrapper without obvious injection vulnerabilities or hardcoded secrets, the dependency chain represents the largest security risk. Immediate action should be taken to update all dependencies to current versions, particularly the Gradle plugin and Android framework libraries. No SQL injection, XSS, or infrastructure misconfigurations were identified in the provided file structure.

  • High · Outdated Gradle Build Plugin — build.gradle (classpath 'com.android.tools.build:gradle:4.0.0'). The project uses gradle:4.0.0 which is outdated and may contain known security vulnerabilities. The current stable version is significantly newer (7.x+), and older versions may lack important security patches. Fix: Update to the latest stable version of the Android Gradle Plugin (7.0.0 or later). Review release notes for breaking changes and test thoroughly.
  • High · Outdated Robolectric Dependency — build.gradle (robolectricVersion = '4.3.1'). Robolectric 4.3.1 is outdated (released in 2020). Newer versions contain bug fixes and security improvements. Current stable versions are 4.9.x or later. Fix: Update Robolectric to version 4.9.1 or later to receive latest security patches and bug fixes.
  • Medium · Outdated AndroidX Dependencies — build.gradle (AndroidX dependencies block). Multiple AndroidX libraries are pinned to old versions: fragment:1.2.5, appcompat:1.1.0, annotation:1.1.0 (released in 2019-2020). These should be updated to current versions to receive security patches and feature improvements. Fix: Update all AndroidX dependencies to their latest stable versions: fragment to 1.6.x+, appcompat to 1.6.x+, annotation to 1.7.x+. Test for compatibility issues.
  • Medium · Outdated Mockito Dependency — build.gradle (mockito = 'org.mockito:mockito-core:3.3.3'). Mockito 3.3.3 is outdated (released in 2020). Current version is 5.x+ with multiple security and stability improvements in between. Fix: Update Mockito to version 5.2.1 or later for the latest security patches and improvements.
  • Low · Deprecated Build Tool Repository — build.gradle (repositories section). The project uses 'jcenter()' repository which is deprecated and no longer maintained by JFrog. While functional, it's officially deprecated as of May 2021. Fix: Remove jcenter() from repositories configuration. Ensure all dependencies are available on mavenCentral() or Google Maven repositories.
  • Low · Missing Dependency Version Constraints — build.gradle. While most dependencies specify versions, there's no explicit version constraint strategy documented for transitive dependencies, which could lead to unexpected updates. Fix: Consider using dependency locking (gradle lockfile) or explicit version constraints for all transitive dependencies to ensure reproducible builds.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tbruyelle/RxPermissions — RepoPilot