No description
Find a file
KaKi87 0c3b442f77 Derive app name from package ID for tagged main builds.
Tag pushes set GITHUB_REF_NAME to the tag, so branch-based naming left stable APKs as Soul2⁺ Browser.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 00:32:46 +02:00
.github/workflows Skip APK builds for tags that are not on main. 2026-09-11 19:27:47 +02:00
app Fix Find in page taking a stale URL-bar query (#113) 2026-09-11 23:35:25 +02:00
bundled-warp Skip redundant CI rebuilds for soulamz and tooling (#85) 2026-09-03 08:10:34 +02:00
native/soulamz Add Cloudflare WARP (#58) 2026-08-17 02:07:27 +02:00
original-dex Decompile and recreate Soul Browser v1.4.85 with APK CI builds (#1) 2026-08-10 16:07:14 +02:00
prebuilts Skip redundant CI rebuilds for soulamz and tooling (#85) 2026-09-03 08:10:34 +02:00
screenshots Update feature showcase 2026-08-17 23:38:24 +02:00
scripts Derive app name from package ID for tagged main builds. 2026-09-12 00:32:46 +02:00
sources Fix Find in page taking a stale URL-bar query (#113) 2026-09-11 23:35:25 +02:00
splits Decompile and recreate Soul Browser v1.4.85 with APK CI builds (#1) 2026-08-10 16:07:14 +02:00
.gitignore Ignore locales_config.xml locally; CI force-commits updates. 2026-09-07 16:58:00 +02:00
AGENTS.md Build and release stable APKs only on main tags. 2026-09-10 18:45:43 +02:00
exodus_privacy_report_v1.4.85-485.txt Sort app permissions alphabetically 2026-08-13 22:23:43 +02:00
exodus_privacy_report_v2_latest.txt [skip ci] Update Exodus Privacy report. 2026-09-11 22:23:28 +00:00
README.md Update README 2026-09-12 00:20:12 +02:00
VERSION Update version 2026-09-12 00:21:21 +02:00

Soul2 Browser

Get it on Obtainium

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" ?
A: The repository cannot be open source for the simple reason that the original Soul Browser is proprietary, therefore any third-party redistribution (including this one) is illegal, despite the circumstances.

Q: Why use Soul's bugtracker ?
A: The hope is Soul's creator will eventually notice the continued interest shown by the community for their app, and decide to resume maintenance and backport the added improvements, at which point this modding project will have achieved its goal and be terminated. Think of this as fanfic.

 
🆕 Ads, trackers & in-app purchases removed 🆕 Website-specific dark theme 🆕 More display settings
🆕 Tab & URL long-press menu improvements 🛠️ YouTube Picture-in-Picture 🛠️ JS downloads
🆕 Eruda DevTools 🆕 Image title/alt text 🆕 Cloudflare WARP

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.

Added share & download buttons to the preview toolbar. Implemented in cc7300c.

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.

Website data in backup

Save logged in sessions in your Soul Browser backup so you no longer have to log back into websites when doing a restore.

Implemented in f537c26.

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.

Copy/share URL without closing : the "Copy URL" and "Share URL" items from the preview context menu no longer uselessly close the preview on click. Implemented in 249b015.

Tab bar long-press menu improvements

Tab favicon & full title : long-press a tab to see its details just like a hover on desktop would make a tooltip appear. Implemented in 8c6bec1.

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.

Text selection long-press menu improvements

Items toggling & sorting : toggle selected text long-press menu items. Implemented in fb8f40f.

"Search in preview" & "Find in page" : perform quick actions from selected text without copy/pasting. Implemented in 509cf1b.

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.

Drag-n-drop without triggering multi-select : prevent displaying checkboxes when just wanting to move tabs around. Implemented in c30b9da.

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.

"Whole world" & "case-sensitive" for "Find in page" : just like desktop Firefox, cause even desktop Chrome doesn't have it. Implemented in b6d8280.

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. Optional advanced "preload" setting initializes Eruda on every page (hidden) so the menu can open it with logs already captured. Implemented in 0200adc and 48bc818.

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.

"Download link" in long-press menu : the equivalent of "Save link as..." on desktop. Implemented in 1ff72c4.

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 & blob:// file downloads

Downloads generated from web apps would always be named downloadfile.txt even when it was supposed to be Important document.pdf. Fixed in 9802419.

Downloads generated with a blob:// URL would just never fire. Fixed in 0e33b30.

Same with downloads generated with a non-image data: URL. Fixed in c1dc13c.

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.

"Incognito tab" listed twice in preview mode menu : the menu item was duplicated. Fixed in 8e5a6f3.

From address bar to "Find in page" : when clicked fast enough (before the search engine autocompletion results appear), only the first letter of the former's query would make it to the latter. Fixed in c322a12.

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.

Bottom bar overlaps page content

This is an old Soul issue, where, on some pages, sometimes after several clicks, the webview starts expanding below the bottom bar and the latter starts ovelapping the former.

Unfortunately, the issue occurs too rarely for a reliable reproduction scenario to be determined. Any help with that is welcome in #363 !

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/.

Source tree vs release APK: Git stores the testing application ID (net.kaki87.soul2.testing, Soul2⁺ Browser). Feature-branch builds should not rewrite package metadata. The stable Soul2 Browser APK (net.kaki87.soul2) is built on CI when a tag on main sets SOUL_PACKAGE_ID. build_date.xml and soul2_info.xml are generated at build time (not committed). The in-app Information text is defined in the README <!-- BEGIN INFO --> section.

The build script:

  1. Merges density-specific resources from split APKs in splits/
  2. Syncs public.xml resource IDs from the original R classes
  3. Rebuilds the base APK from app/ using Apktool
  4. Injects the original classes2.dex desugar libraries
  5. Injects OCR / WARP helper dexes (classes5classes7)
  6. Merges native libraries from ABI split APKs and bundled-warp/
  7. 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 non-main branch push. Plain pushes to main and tags whose commit is not on main skip the APK job (i18n publish still runs on main). When a tag whose commit is on main is pushed, CI builds the stable APK, uploads it, runs εxodus standalone, and may commit exodus_privacy_report_v2_latest.txt, locales_config.xml, and refreshed prebuilts back to main. bundled-warp/lib/ is in the checkout (gitignored for local adds; CI updates with git add -f when native/soulamz inputs change). Report-only / prebuilt 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

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.