unblock-jitpack-expo
v0.1.0
Published
Rescue an Android / Expo / React Native Gradle build when jitpack.io (or any Maven repo) is unreachable — vendors the artifact into android/local-maven and wires it via Gradle exclusiveContent.
Maintainers
Readme
unblock-jitpack-expo
Rescue an Android / Expo / React Native Gradle build when jitpack.io (or any other Maven repo) is unreachable — vendor the failing artifact into your repo and route Gradle around the blocked upstream via
exclusiveContent.
If you've hit this — usually on some Indian ISPs (Jio / Airtel / ACT), on a corporate proxy, or on airgapped CI — you know the pain:
Could not resolve com.github.Dimezis:BlurView:version-2.0.6.
> Could not GET 'https://www.jitpack.io/com/github/Dimezis/BlurView/...'.
> Connect to www.jitpack.io:443 [104.26.x.x, ...] failed: Connection timed outThe dependency is fine. The path to it is not. This CLI fixes it once and
for all: it copies the artifact from your Gradle cache into
android/local-maven/, patches android/build.gradle with an
exclusiveContent block that scopes ONLY that coord to the local repo, and
leaves everything else on google() / mavenCentral() / jitpack untouched.
Fix in under a second
Grab the failing coord straight from your Gradle error (the Could not resolve
<group>:<artifact>:<version> line) and run:
npx unblock-jitpack-expo@latest add <your-group>:<your-artifact>:<your-version> --yesConcrete example (this one happens to be BlurView, but any Maven
coordinate works — .aar Android libs, .jar Java libs, any version string):
npx unblock-jitpack-expo@latest add com.github.Dimezis:BlurView:version-2.0.6 --yesOr run it with no coord and paste the whole error line when prompted — the CLI extracts the coord for you.
Under the hood: copy the artifact from your local Gradle cache into
android/local-maven/, patch android/build.gradle with a scoped
exclusiveContent block. Done in ~300 ms.
What it looks like
› Project: my-expo-app
android/ : android
build.gradle : android\build.gradle
────────────────────────────────────────────────────────────
[1/1] Vendoring com.github.Dimezis:BlurView:version-2.0.6
✔ Copied 3 file(s) into android\local-maven\com\github\Dimezis\BlurView\version-2.0.6/
› Patching android\build.gradle ...
✔ inserted managed exclusiveContent block into repositories { }
wired: com.github.Dimezis:BlurView
✔ Wrote android\local-maven\README.md
────────────────────────────────────────────────────────────
✔ Done. Verify with:
cd android && ./gradlew :app:dependencies --configuration debugRuntimeClasspath | rg BlurView
npx expo run:androidInstall & run — pick your package manager
You don't need to install anything globally. Run it directly with the runner
that ships with your package manager. Always pin @latest so you pick up
new heuristics and bug fixes.
# npm
npx unblock-jitpack-expo@latest
# pnpm
pnpm dlx unblock-jitpack-expo@latest
# yarn (>= 2 / berry)
yarn dlx unblock-jitpack-expo@latest
# bun
bunx unblock-jitpack-expo@latestOr install it globally if you'll use it a lot:
npm i -g unblock-jitpack-expo
pnpm add -g unblock-jitpack-expo
bun add -g unblock-jitpack-expoThe CLI will also tell you when a new version is available (once a day at
most, cached; never blocks the run). Follow the printed hint — a
npx unblock-jitpack-expo@latest ... invocation will grab it.
What it does
Run from your Expo / React Native / bare-Android project root and:
Detects your project layout (
package.json,android/,android/build.gradleor.kts) and refuses to run outside a valid app directory.Takes the failing Maven coord — as a positional argument, from a
--log <file>build log, or from a pasted line in interactive mode.Finds the artifact (
.aar/.jar+.pom+ optional.module) in your local Gradle cache (~/.gradle/caches/modules-2/files-2.1/...) and copies it intoandroid/local-maven/<group-as-path>/<artifact>/<version>/.Patches
android/build.gradle(or.kts) with a managedexclusiveContentblock that includes ONLY your vendored coord(s):allprojects { repositories { // >>> unblock-jitpack-expo: BEGIN (managed - do not edit by hand) <<< exclusiveContent { forRepository { maven { name = "UnblockJitpackLocalMaven" url = uri("${rootProject.projectDir}/local-maven") metadataSources { mavenPom(); gradleMetadata() } } } filter { // one includeModule() per coord you added; example shown: includeModule('com.github.Dimezis', 'BlurView') } } // <<< unblock-jitpack-expo: END >>> google() mavenCentral() maven { url 'https://www.jitpack.io' } // left in place for other coords } }Writes
android/local-maven/README.mdand adds an un-ignore rule to.gitignore/.easignoreif either would sweep away vendored.aarfiles.Prints a verification command you can paste back into the terminal.
The block is idempotent — re-running with more coords merges into the same block; it never duplicates.
Common usage
Non-interactive with the coord you already saw in the error (fastest, CI-safe):
npx unblock-jitpack-expo@latest add com.github.Dimezis:BlurView:version-2.0.6 --yesInteractive — run with no args, paste the coord (or the whole error line) when prompted:
npx unblock-jitpack-expo@latestMultiple coords at once:
npx unblock-jitpack-expo@latest add \
com.github.Dimezis:BlurView:version-2.0.6 \
com.github.SomeOrg:some-lib:1.2.3 --yesExtract coords from an existing Gradle log file:
./gradlew :app:assembleDebug 2> build.log || true
npx unblock-jitpack-expo@latest add --log build.log --yesAlso vendor runtime transitive deps found in the .pom:
npx unblock-jitpack-expo@latest add com.github.Dimezis:BlurView:version-2.0.6 --recurse --yesCheck reachability of a Maven host from this machine:
npx unblock-jitpack-expo@latest check-host www.jitpack.ioVerify an existing vendored setup:
npx unblock-jitpack-expo@latest doctorPoint at a project outside cwd:
npx unblock-jitpack-expo@latest --cwd ~/apps/my-expo-app add com.github.Dimezis:BlurView:version-2.0.6 --yesFull flag reference:
Options:
-v, --version Print CLI version and exit
--yes Non-interactive: assume yes for all prompts
--verbose Verbose diagnostic logging
--no-banner Suppress the startup banner
--cwd <dir> Project root to operate on (defaults to auto-detected)
Commands:
(default) Interactive: prompt for a coord and apply the fix.
add <coord...> Vendor coord(s) and wire them into build.gradle.
--log <file> Also pull coords from a Gradle build log file
--recurse Also vendor runtime deps found in the .pom
doctor Verify the vendored setup is coherent
check-host [host] TCP-test a Maven host (default: www.jitpack.io)
-p, --port <port> TCP port (default: 443)What if the coord isn't in my Gradle cache yet?
The artifact must have been downloaded at least once on a network that can reach the upstream repo. Priority order:
- VPN / phone tether — enable it, run
cd android && ./gradlew :app:assembleDebug --refresh-dependenciesonce (even if the build later fails), then re-run this CLI. - Copy from a teammate — copy
~/.gradle/caches/modules-2/files-2.1/<group>/<artifact>/<version>/into the same path locally, then re-run. - Manual mirror — download
.aarand.pomfrommvnrepository.comor a Sonatype/Nexus mirror, drop them intoandroid/local-maven/<group-as-path>/<artifact>/<version>/, then re-runaddwith the same coord to write thebuild.gradleblock.
The CLI never touches the network for artifact bytes on its own; you keep control over that step.
Requirements
- Node.js ≥ 18.17 (uses stable ESM and native fs APIs)
- A project with:
package.jsonat the project rootandroid/directory (fromnpx expo prebuildor a bare RN project)android/build.gradle(Groovy) orandroid/build.gradle.kts(Kotlin DSL)
Works from any package manager runner: npx, pnpm dlx, yarn dlx, bunx.
No lockfile changes to your project.
Compatibility notes
- Expo prebuild:
expo prebuild --cleanwipesandroid/. If you run that regularly, either keep vendored artifacts under source control (they're small;.aarfiles are typically < 500 KB) or wrap the vendoring in an Expo config plugin.android/local-maven/README.mdis written by the CLI so the intent is discoverable to future you. - EAS Build (remote): works as long as
android/local-maven/**is committed to git and not excluded by.easignore. The CLI adds the un-ignore rule for you if it detects an exclusion. - Kotlin DSL:
android/build.gradle.ktsis supported. The CLI emits KTS syntax when it detects a.ktsroot build script. - Multiple coords / repeat runs: safe. The managed block is merged, not
duplicated. Bumping a version is
<version>/-folder rename + re-runningaddwith the new coord (the block is keyed ongroup:artifact, soincludeModuledoesn't need to change).
Why exclusiveContent and not flatDir or removing the upstream repo?
flatDirskips.pommetadata, so transitive deps disappear and you get crypticNoClassDefFoundErrorat runtime.- Removing the upstream repo from
allprojects.repositoriesbreaks resolution for every other coord that legitimately lives on jitpack. exclusiveContentis explicit, greppable, and Gradle-native: it says "for these specific coords, look ONLY here", and everything else routes through your existing repo declarations untouched.
Contributing
Issues and PRs welcome. The CLI is intentionally dependency-light so it stays
snappy for npx first-use latency.
git clone https://github.com/nikhildhawan/unblock-jitpack-expo
cd unblock-jitpack-expo
npm install
npm run build
node dist/cli.js --helpLicense
MIT. See LICENSE.
