{"id":17008807,"url":"https://github.com/i-e-b/miniweb","last_synced_at":"2026-04-16T12:34:11.096Z","repository":{"id":45263604,"uuid":"511896303","full_name":"i-e-b/MiniWeb","owner":"i-e-b","description":"A small framework for building small android apps","archived":false,"fork":false,"pushed_at":"2023-01-30T16:21:06.000Z","size":322,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-27T12:11:17.214Z","etag":null,"topics":["android","css","hot-reload","html","java","javascript","small","web"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/i-e-b.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-08T12:58:32.000Z","updated_at":"2022-11-23T14:50:31.000Z","dependencies_parsed_at":"2023-02-16T09:16:11.967Z","dependency_job_id":null,"html_url":"https://github.com/i-e-b/MiniWeb","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FMiniWeb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FMiniWeb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FMiniWeb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FMiniWeb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/i-e-b","download_url":"https://codeload.github.com/i-e-b/MiniWeb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244958981,"owners_count":20538622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","css","hot-reload","html","java","javascript","small","web"],"created_at":"2024-10-14T05:29:18.670Z","updated_at":"2026-04-16T12:34:11.081Z","avatar_url":"https://github.com/i-e-b.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MiniWeb\nA small framework for building small android apps\n\n## What is it?\n\nA simple set of drivers for the built-in Android WebView that provides\na web-like development environment contained in a single app.\n\nThe app uses as much of the built-in Android system features as possible to result\nin a small final APK. The app plus example pages comes to around 50KB\nwhen built in release mode.\n\n### Road-map\n\n- [ ] **Overlay** - Draw a new view over the current one. Clicking outside of the new view, or clicking 'back' reloads the original view without the overlay.\n- [ ] Implement something big (or at least non-trivial) in this. Add anything found to be missing\n- [ ] Hooks for 'wallet' service, hot code loading / live updates.\n- [ ] Action and progress controls -- template that replaces with a progress display and triggers a back-end task. Another replacement when task completes.\n\n## How it works\n\nThe app is based around a set of self registering \"controllers\". These are classes\nthat register a set of web methods. Each method will return the path of a view\ntemplate and an optional object used to complete that template.\n\nNote that the web client and app server and tightly coupled 1:1, so you can\nget away with directly calling 'server' code from the client in a way you\ncan't with normal web development.\n\nUrls for the app are in the form `app://{controller}/{method}?param=values`\n\nThe app will start in `app://home/index`, which is the same as `app://home`.\n\nTemplates should be in `assets/views`, and the file name should end in `.html`.\nEach template is a fragment of HTML which will be wrapped in a \\\u003cbody\\\u003e tag and\ngiven a default style sheet.\n\nThe default style sheet is in `assets/styles/default.css`\n\n## Calling JavaScript\n\nJavaScript is enabled on the web view, and should work as normal.\n\nIt is possible to call directly from JavaScript to the host app. An object called `manager` is\navailable to all scripts. This exposes any methods in the `JsCallbackManager` class which\nare decorated with the `@JavascriptInterface` annotation.\n\nThere are some limitations around the kind of data that can be passed to `manager`.\nIt sometimes needs an intermediary call in the page to serialise an object to send back to the app.\n(see the 'Forms and parameters' example)\n\n## Templating\n\nThe view templates are mostly plain HTML, with the ability to inject values from\nthe controller method.\nTemplate holes can be put anywhere in a template -- text, tags, scripts, etc.\n\n### Simple values\n\nValues are copied from the model object into 'holes' in the html, which start with `\u003c_\u003e` and end with `\u003c/_\u003e`.\nFor example, with a model containing `public String greeting = \"hello\";` and a template with\n`\u003cp\u003e\u003c_\u003egreeting\u003c/_\u003e world\u003c/p\u003e`, then the final result is `\u003cp\u003ehello world\u003c/p\u003e`\n\nNote: the field name used with a template hole is case sensitive, and must be a field on the model,\nnot a function or method.\n\nFor injection in other HTML tags and attributes, and for injecting into `\u003cscript\u003e` tags,\nyou can use \u003ccode\u003e`_$`modelField`$_`\u003c/code\u003e. This only does simple replacements, and can't\ndo any logic, repetition, or sub-views.\n\n### Complex values\n\nYou can reach further into an object hierarchy with a dotted path. See the 'templating' demo page for\nexamples. It's generally better to restructure your model instead.\n\n### Looping and Conditional output\n\nYou can use a pair of \u003ccode\u003e`\u003c_for model_field\u003e`\u003c/code\u003e and \u003ccode\u003e`\u003c/_for\u003e`\u003c/code\u003e to\nenclose a block of HTML.\n\n* If the `model_field` is a boolean value, the block will be displayed once, and only if the value is `true`\n* If the `model_field` is a list or array, the block will repeat for each item\n* For any other value, the block will be displayed once, and only if the value is not `null`\n\nInside a loop, you can use \u003ccode\u003e`\u003c_\u003e#.`loopItem`\u003c/_\u003e`\u003c/code\u003e to read values from each item.\n\nYou can loop or use a conditional block with a child item. For example:\n```\n\u003c_for people\u003e\n    \u003cp\u003eDear \u003c_\u003e#.name\u003c/_\u003e, we are writing regarding account \u003c_\u003e#.accountNumber\u003c/_\u003e...\u003c/p\u003e\n\u003c/_for\u003e\n```\n\n### Nesting loops\n\nYou can put a `\u003c_for ...\u003e` loop inside another.\n\nYou can loop over an item in a loop using `\u003c_for #.item\u003e`\n```\n\u003c_for accounts\u003e\n    \u003cp\u003e\u003c_\u003e#.userName\u003c/_\u003e has these items\u003c/p\u003e\n    \u003col\u003e\n    \u003c_for #.basketItems\u003e\n        \u003cli\u003e\u003c_\u003e#.name\u003c/_\u003e x \u003c_\u003e#.quantity\u003c/_\u003e\u003c/li\u003e\n    \u003c/_for\u003e\n    \u003c/ol\u003e\n\u003c/_for\u003e\n```\n\n## Editing HTML\n\nIf you use Android Studio, some basic HTML editing tools are available.\nYou might want to use a different one of the IntelliJ suite of tools for better support.\n\nAs well as 'hot reload' described below, you can open a HTML page in your browser for basic design\nusing `View` \u003e `Open in Browser` in the Android Studio main menu:\n\n![View, Open in Browser](https://github.com/i-e-b/MiniWeb/raw/main/_docs/view-in-browser-android-studio.png)\n\n## Emulator Host and Hot Reload\n\nMiniWeb supports \"hot-reload\" of pages and assets when running under an emulator\n(i.e. during development). You need to run the Emulator Host tool (`TinyWebHook`)\nor a similar compatible service.\n\nIf you want to connect to the hot-reload service from a real device, you will need\nto have an active `adb` connection, and ensure port `1310` is 'reversed'.\nThis can be done with `adb reverse --no-rebind tcp:1310 tcp:1310`.\nThe `adb` tool is installed to `C:\\Users\\{user}\\AppData\\Local\\Android\\Sdk\\platform-tools`\nif using Android Studio for Windows.\n\nThe Emulator Host tool **must** be running when your app first starts, otherwise\nthe hot-reload system will be disabled.\n\nIf that is working correctly, changes to files in the `assets` folder will be\nmonitored, and if any files being used by the current page (including linked \nresources) will cause the page to refresh with the updated resources.\n\nNote: the controller is not called during hot-reload. The template model used\nto render the page is kept to allow redraw without calling the controller.\nThis means that any external effects of your page (like reading from, *or* writing\nto, a database) will not be repeated for a hot-reload.\n\nThe Android Emulator connects to the host over IP address `10.0.2.2`.\nThe MiniWeb class at `e.s.miniweb.core.EmulatorHostCall` has a few methods to make\nHTTP calls to the host over this address (with very short connection timeout, so\nthat failures don't pause the app significantly).\n\nIf there is a HTTP server listening on port `1310`, MiniWeb will try to communicate\nwith it using a very simple protocol.\n\n### TinyWebHook\n\nThere is a `TinyWebHook` dotnet app that supports the MiniWeb Hot-Host Protocol.\n`TinyWebHook` also supports a `/` path for test use.\n\nThis must be run with administrator access under Windows, or with http binding\naccess on other systems (`root` should be ok for development).\n\nCall `TinyWebHook` with the path to your Android app's `assets` folder.\n(e.g. `C:\\gits\\MiniWeb\\app\\src\\main\\assets`)\n\n### Hot-Host Protocol\n\n#### Version\n\n```\nhttp://10.0.2.2:1310/host\n```\n\nThis should return `ANDROID_EMU_HOST_V1`; If this path\nfails or returns a different value, Hot Reload will **not** be active.\nThis is agreed in code at `e.s.miniweb.core.EmulatorHostCall#HOST_UP_MSG` and `TinyWebHook.Program.HostUpMsg`\n\n#### Time\n\n```\nhttp://10.0.2.2:1310/time\n```\n\nThis should return the current server time as **UTC**\nin the format `yyyy-MM-dd HH:mm:ss`.\n\n#### Assets\n\n```\nhttp://10.0.2.2:1310/assets/{path to asset}\n```\n\nThis should return the file contents for the asset requested. The path is allowed\nto be any path into the assets folder.\nThe path may **not** contain `..` or `.` elements.\n\n* If the host returns a 200 status, the content will be used instead of the content in the APK of the running Android app.\n* If the host returns a 404 status, the file will be treated as removed, regardless if its presence in the APK.\n* If the host returns any other status, the file will be loaded from the APK as normal.\n\n#### Last touch\n\n```\nhttp://10.0.2.2:1310/touched/{path to asset}\n```\n\nThis should return the modified date of the file requested.\nThe Android app will request and store this when a file is loaded through the host, and\nwill periodically request again while the page is being displayed.\n\n* If the host returns 200, and the date has **not** changed, the Android app takes no action\n* If the host returns 200, and the date **has** changed, the Android app will try to reload the current page with existing data on the updated template\n* If the host returns any other code, the Android app takes no action.\n\n#### Last page push\n\n```\nhttp://10.0.2.2:1310/push\n```\n\nThe Android app should `POST` to this when it renders a page.\nThe Emulator Host will then make this available on the host machine\n\n#### Last page get\n\n```\nhttp://127.0.0.1:1310/get\n```\n\nReturns the body of the last page that was pushed by the Android app.\nIf nothing has been pushed yet, the page will be blank\n\n## Other bits\n\nTest cert jks password: `deploy.jks`\nDo **not** use this certificate for your app, it is public and should only be used for testing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-e-b%2Fminiweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fi-e-b%2Fminiweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-e-b%2Fminiweb/lists"}