| .github/workflows | ||
| app | ||
| bundled-warp | ||
| native/soulamz | ||
| original-dex | ||
| screenshots | ||
| scripts | ||
| sources | ||
| splits | ||
| .gitignore | ||
| AGENTS.md | ||
| exodus_privacy_report_v1.4.85-485.txt | ||
| exodus_privacy_report_v2_latest.txt | ||
| README.md | ||
| VERSION | ||
Soul2 Browser
Soul2 Browser is a decompiled & modded source for Soul Browser by SoulSoft, which hasn't been updated since v1.4.85 on December 10th, 2025 (since exactly 7 months at "fork" time).
- Fixes long-standing bugs & add long-awaited features ;
- Reports & requests welcome at the official issue tracker ;
- Original decompiled code & patches both source-available and welcoming contributions ;
- Out of respect for the original developer, all changes to the project will remain minimal and faithful to the original works in terms of branding, architecture, interface, experience and features.
- App is named Soul2 Browser (
net.kaki87.soul2) for stable builds and Soul2⁺ Browser (net.kaki87.soul2.testing) for testing builds; both support configuration import/export in Settings -> Backup between each other and the official app.
LLM usage disclosure : the modding code mostly being Smali, i.e. the assembly language (barely readable layer above bytecode) for Android's "Java", a vast majority of it is LLM-generated, but also extensively tested, both in emulator automatically and on a real phone manually, not to mention I'm daily-driving it.
Q&A
|
Q: Why "source-available" ? |
|
Q: Why use Soul's bugtracker ? |
Exclusive features
Privacy
All tracking, advertising and in-app purchase services were removed, as per this summarized diff between the official app's Exodus Privacy report & the modded one's.
Diff
--- v1.4.85
+++ v2.0.0
=== Information
-- App version: 1.4.85
+- App version: 2.0.0
-- App version code: 485
+- App version code: 2000000
-- App name: Soul
+- App name: Soul2 Browser
-- App package: com.mycompany.app.soulbrowser
+- App package: net.kaki87.soul2
-- App permissions: 27
+- App permissions: 22
- - android.permission.ACCESS_ADSERVICES_AD_ID
- - android.permission.ACCESS_ADSERVICES_ATTRIBUTION
- - android.permission.ACCESS_ADSERVICES_TOPICS
- android.permission.ACCESS_COARSE_LOCATION
- android.permission.ACCESS_FINE_LOCATION
- android.permission.ACCESS_NETWORK_STATE
- android.permission.USE_FINGERPRINT
- android.permission.WAKE_LOCK
- com.android.launcher.permission.INSTALL_SHORTCUT
- - com.android.vending.BILLING
- - com.google.android.gms.permission.AD_ID
- - com.mycompany.app.soulbrowser.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
+ - net.kaki87.soul2.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION
- App libraries:
- org.apache.http.legacy
- - android.ext.adservices
-=== Found trackers: 3
+=== Found trackers: 0
- - Google Firebase Analytics
- - Google AdMob
- - OpenTelemetry (OpenCensus, OpenTracing)
Implemented in 94e63e5 and f4b02ef.
YouTube background playback
As it is distributed on Google's Play Store, the official app doesn't support background playback for Google's YouTube.
This mod does and will not have this constraint, so you can now play YouTube in the background without having to use PiP.
Implemented in af43286.
PDF previews
No need to download PDFs before reading them anymore. Implemented in b16124c.
Website-specific dark theme (#155)
Disable force-dark specifically for websites that are already dark (or look bad with it). Implemented in 32481a1.
The opposite, however, is not possible : the webview API does not allow having most websites light by default and a few exceptionally dark.
Cloudflare WARP
Routes HTTP requests for page loading & file downloading through Cloudflare's VPN & DNS service, increases safety on public networks and bypasses ISP blocks.
⚠️ Does not, however, reliably hide your IP (WebRTC, etc.), bypass geographic restrictions, nor even allow choosing the egress location.
If using AdGuard or other VPN-level content blockers, whitelist Soul for use with WARP.
Powered by skye-z/amz. Implemented in d1ec2a8.
Page preview improvements
Links & image long-press menu : was completely unavailable in preview mode, now is. Implemented in 5f3e8d4
URL bar location : was hard-coded at the top, can now be at the bottom, or even inline with icon-only close & new tab buttons. Implemented in 0f2b1c0.
New tab without reload : the Preview New tab button now keeps the existing WebView instead of opening the URL in a fresh tab. Implemented in 2664b4c.
Tab bar long-press menu improvements
Items toggling & sorting : toggle tab long-press menu items just like link/image long-press menu items. Implemented in 862ec31 and c258d50.
Close tab : simply a new menu item allowing closing a tab in the background. Implemented in be46c27.
Tab homepage : In the fashion of Zen Browser's pinned tabs, pin tabs to a specific homepage by long-pressing the new Homepage button, then simple-click it to automatically navigate back to it. Implemented in ef6d47f.
Tab list improvements
Copy multiple tab URLs (#63, #99) : copy a few or all tabs' URLs as a newline-separated list to the clipboard. Implemented in bef3fd9.
Range selection : select a tab, then long-press another, to automatically select all in between. Implemented in a445b61.
Misc
Default tab group color : was hard-coded to red, now customizable in settings. Implemented in a0499b3.
Default image link long-press menu tab : was hard-coded to whatever was last used, now customizable in settings. Implemented in afa8916.
Full timestamps in history : With hours, minutes and seconds. Implemented in 04b85de.
URL bar long-press items toggling & sorting : same as tab bar. Implemented in 977e078.
JSON viewer : powered by pd4d10's port of Firefox's JSON Viewer. Implemented in 8d4aa8364.
Eruda DevTools : knockoff element inspector, network logging & JS console, powered by Eruda. Implemented in 0200adc.
Advanced option to disable last state restoration : prevents webapps from showing outdated information when loading after suspension or restart. Implemented in c3f57ee.
Image title/alt text on long-press (#80) : was hard-coded to the image's URL, now provides a more useful description when available. Implemented in 101b5f2.
Exclusive bugfixes
YouTube Picture-in-Picture
The official app shows "video unavailable" when trying to use PiP on YouTube. Fixed in 7902fe5.
Search by image
Google would return 404. Fixed in cad7450.
JS-triggered file downloads
They would always be named downloadfile.txt even when it was supposed to be Important document.pdf. Fixed in 9802419.
Misc
Focus steal from foreground on system quick settings/notifications pane pull-down : Android kills memory-hungry apps when the user pulls down the notifications pane,
which may kill Soul's webview, which in return brings itself to the foreground even when the launcher or another app was active, and respawns the webview process. Fixed in 7259a2a.
Non-JS URL ending with *.user.js triggers userscript install : a page showing a preview of a userscript rather than the raw file (e.g. on a git platform) will unexpectedly trigger the userscript install prompt. Fixed in 50f75c3.
PDF translation fixed on "Updating the text module" : translation models were downloaded using Google Play Services, which doesn't work on GApps-free devices. Fixed in e2c1896.
Known bugs
YT PiP controls
PiP controls (⏪/⏯️/⏩) don't work on YouTube, the workaround consists in going fullscreen then using YouTube's controls and going back to PiP if desired.
Other sites aren't affected.
It is unknown whether this bug was inherited from the official app (non-testable due to PiP being broken on the official app) or introduced by the PiP fix (introduced due to PiP being broken on the official app).
Repairing this has been attempted multiple times, without success.
Buggy WebView versions
Some Android System WebView versions between 148 and 149 are known to cause issues with long-press, e.g. menus on images, links, image links, as well as text selection.
In Soul, this translates into the inability to interact with pages (as if frozen) after using long-press twice, the wrong long-press menu appearing when clicking elements of different types, etc.
Project structure
| Path | Description |
|---|---|
app/ |
Apktool decompilation (smali + resources). This is the buildable source. |
sources/java/ |
JADX-decompiled Java sources for reference and readability. |
sources/resources/ |
JADX-extracted resources. |
original-dex/ |
Original classes2.dex (Java 8+ desugar libs; apktool cannot recompile these reliably). |
splits/ |
Split APK configs (native libs, density) from the original XAPK bundle. |
scripts/build.sh |
Local and CI build script. |
native/soulamz/ |
Go wrapper around unofficial amz WARP HTTP proxy (built to bundled-warp/). |
sources/warp-runtime/ |
Java helpers for WARP prefs, ProxyController, and settings UI (injected as classes7.dex). |
Build
Requirements: Java 21+, curl, zip, keytool, jarsigner. Optional: Android SDK zipalign.
./scripts/build.sh
Output APKs are written to dist/.
The build script:
- Merges density-specific resources from split APKs in
splits/ - Syncs
public.xmlresource IDs from the originalRclasses - Rebuilds the base APK from
app/using Apktool - Injects the original
classes2.dexdesugar libraries - Injects OCR / WARP helper dexes (
classes5–classes7) - Merges native libraries from ABI split APKs and
bundled-warp/ - Signs the APK with apksigner (v1+v2+v3)
Local builds sign with a generated keystore/debug.keystore (passwords android / alias soulbrowser) unless you set:
| Variable | Purpose |
|---|---|
SOUL_KEYSTORE |
Path to a PKCS12/JKS keystore |
SOUL_KEYSTORE_PASSWORD |
Keystore password |
SOUL_KEY_PASSWORD |
Key password |
SOUL_KEY_ALIAS |
Key alias (default: soulbrowser) |
The rebuilt APK is a standalone install (split APK metadata removed from the manifest).
CI
GitHub Actions workflow .github/workflows/build-apk.yml builds and uploads APK artifacts on every push. On main, the same workflow also runs εxodus standalone against the signed APK and commits exodus_privacy_report_v2_latest.txt. Report-only commits include [skip ci] and are ignored by path filters so they do not rebuild the APK or re-run the analysis.
Release signing uses repository secrets (never committed):
| Secret | Purpose |
|---|---|
SOUL_KEYSTORE_BASE64 |
Base64-encoded keystore file |
SOUL_KEYSTORE_PASSWORD |
Keystore password |
SOUL_KEY_PASSWORD |
Key password |
SOUL_KEY_ALIAS |
Key alias (optional; defaults to soulbrowser) |
Example to rotate secrets from a local keystore:
base64 -w0 keystore/release.keystore | gh secret set SOUL_KEYSTORE_BASE64
printf '%s' "$STORE_PASS" | gh secret set SOUL_KEYSTORE_PASSWORD
printf '%s' "$KEY_PASS" | gh secret set SOUL_KEY_PASSWORD
printf '%s' soulbrowser | gh secret set SOUL_KEY_ALIAS
Decompilation details
- APK source: Downloaded from APKPure via apkeep
- Apktool: 2.10.0 — smali/resources decompilation and rebuild
- JADX: 1.5.0 — Java source decompilation for reference
Legal notice
Soul Browser is developed by SoulSoft and distributed on Google Play. This repository contains decompiled code for educational and interoperability purposes. All rights belong to the original copyright holders.









