A minimal Android share-sheet target that uploads files (and text) to a
self-hosted MicroBin instance, mirroring the request contract of mb-cli. It
adds an Upload to MicroBin entry to the system share sheet. Files are sent
with the configured uploader_password; text pastes are sent without one, since
the reference instance requires the password for file uploads only.
There is intentionally no admin/list/delete surface — open the instance in a browser for that.
- Share one or more files → each is POSTed to
/uploadwith the saved file password; the resulting…/p/{key}links are shown and copied to the clipboard. - Share text → POSTed to
/uploadas a paste with an empty password. - Tapping the app icon opens a small settings screen (instance URL, file password, default expiration and privacy, plus a connection test).
The upload path reproduces mb-cli exactly and was validated against a live
instance:
POST {base}/upload,multipart/form-data, fixedContent-Length(non-chunked).- Fields, in order:
content,expiration,burn_after,privacy,syntax_highlight,uploader_password,encrypt_client,plain_key,random_key,encrypted_random_key, then afilepart for file uploads. - Redirects are not followed; the
Locationheader of the302is read directly. A location ending in/incorrectmeans the password was rejected; otherwise the final path segment is the key and the share link is{base}/p/{key}.
The Uploader class has no Android dependencies, so its multipart output can be
diffed against the reference client byte-for-byte.
AndroidManifest.xml
build.sh no-Gradle build (aapt2 / d8 / zipalign / apksigner)
src/ph/dgsd/mbshare/
Uploader.java multipart POST, redirect + /incorrect handling
Prefs.java SharedPreferences configuration
ShareActivity.java ACTION_SEND / ACTION_SEND_MULTIPLE handler
SettingsActivity.java launcher + configuration screen
res/values/strings.xml
res/values/arrays.xml expiration / privacy option values
res/layout/activity_share.xml
res/layout/activity_settings.xml
No third-party dependencies: the app compiles against android.jar alone, which
is what makes the Gradle-free build practical. The launcher icon references the
framework drawable ic_menu_upload; drop in a real icon later if desired.
Prerequisites: a JDK (javac, keytool), Android SDK build-tools
(aapt2, d8, zipalign, apksigner), a platform android.jar, and zip.
./build.shThe script auto-detects ANDROID_SDK_ROOT (or set it explicitly) and picks the
highest installed build-tools and platform. Override with BUILD_TOOLS,
PLATFORM, MIN_SDK, TARGET_SDK, OUT.
If build-tools or a platform are missing:
sdkmanager "build-tools;34.0.0" "platforms;android-34"The script signs in this order of precedence:
-
Java keystore — set
KEYSTORE(and optionallyKEY_ALIAS,KEYSTORE_PASS,KEY_PASS):KEYSTORE=~/keys/release.jks KEY_ALIAS=release \ KEYSTORE_PASS=... KEY_PASS=... ./build.sh -
Platform PEM + PKCS#8 — sign with the platform key so the app can run as
android:sharedUserId="android.uid.system"or live inpriv-appon your ROM:PLATFORM_CERT=~/keys/platform.x509.pem \ PLATFORM_KEY=~/keys/platform.pk8 ./build.sh
-
Debug key — if nothing is supplied, a throwaway
build/debug.keystoreis generated so the build completes.
The app requests only INTERNET (a normal permission), so platform signing and
system placement are optional — a plain user install works. Sign with the
platform key only if you specifically want it in priv-app.
adb install -r mbshare.apkTo install as a system app on your ROM, place the platform-signed APK under
priv-app (or product/priv-app) in the usual way for your build. No
privileged permissions are declared, so this is not required for normal use.
- Open the app once; set the instance URL and the file upload password; Save.
(Use Test connection to confirm reachability and that the instance
advertises the
uploader_passwordfield.) - From any app, Share → Upload to MicroBin. The link(s) are shown and copied to the clipboard; Open launches the first in a browser.
- Password storage. The file password is kept in plain text in the app's
private
SharedPreferences(/data/data/ph.dgsd.mbshare/shared_prefs/), readable only by the app's UID and root. This is a deliberate tradeoff for a single-user utility and avoids pulling inandroidx.security. SubstituteEncryptedSharedPreferencesinPrefsif a stronger guarantee is wanted. - Temp copy. Shared content is copied to the app cache before upload so the
exact byte length is known for the fixed-length POST regardless of what the
content provider reports for size. The copy is deleted after each item. For
routine shares (photos, documents, screenshots) the transient disk use is
negligible; adjust
copyToCacheif streaming very large files directly is preferred. - Expiration cap. The instance caps expiration at
1week; the spinner offers only values it accepts. - Defaults. The instance URL defaults to
https://p.dgsd.phand privacy topublic; change these in settings as needed.