Background WebViewS (FREE)

:globe_with_meridians: WebViewS — a full-featured browser component for Kodular

WebViewS is an extension that turns a plain WebView into a real mini-browser: address & search bar with voice input, pull-to-refresh, Chrome-style long-press menu, JavaScript tools, a built-in JSON decoder, cookie control, dark mode, desktop mode, ad blocking, page-text scraping, file upload with camera, screenshots, PDF export and much more — all through simple blocks, no JavaScript knowledge required.

Package: com.webviews · Category: Extension (non-visible component) · Platform: Android


:sparkles: Feature overview

:magnifying_glass_tilted_right: Search / address bar Type a URL or a search query. Mic button for voice search. Colors, hint and visibility are customizable.
:backhand_index_pointing_down: Pull to refresh Swipe down at the top of a page to reload it (like Chrome).
:backhand_index_pointing_up: Long-press menu Long-press a link, image, video or audio → open, open in new window, download, copy address, share. Long-press on text → normal Android text selection with Copy.
:scroll: JavaScript tools Run JS, inject CSS, run scripts on every page load, two-way communication page ⇄ app.
:puzzle_piece: JSON blocks JsonDecode, JsonGet, JsonPluck… turn JSON into lists and dictionaries in one block.
:computer_mouse: No-JS page control ClickElement, FillInput, GetElementText, ScrollToElement, GetPageText using plain CSS selectors.
:cookie: Cookies Read, set, delete one cookie or clear all — perfect for login flows.
:crescent_moon: Dark mode / :desktop_computer: Desktop mode / :input_latin_uppercase: Font size One property or one block each.
:shield: Ad & tracker blocker Built-in domain list + your own list.
:camera_with_flash: Screenshot & PDF Save the visible page as PNG or print/save it as PDF.
:open_file_folder: File upload, camera, microphone <input type="file"> works, camera capture works, web pages can use camera/mic (opt-in).
:inbox_tray: Downloads Files go to the Download folder with a system notification.
:receipt: View source Show the page source inside the component, get DOM or raw HTML.
:bar_chart: Scroll events OnScrollChanged and OnScrolledToBottom for infinite-scroll style loading.

:rocket: Installation & setup (step by step)

  1. Import the .aix file into your Kodular project (Extensions → Import extension).
  2. In the Designer, add a VerticalArrangement (or HorizontalArrangement) to your screen.
    Set its Width and Height to Fill parent. This is the place where the browser will appear.
  3. Add WebViewS from the Extension palette. It is a non-visible component — it shows up under the phone screen, not inside it.
  4. Open the Blocks editor and connect them once, in Screen.Initialize:
when Screen1.Initialize
do  call WebViewS1.SetLayout  layout: VerticalArrangement1
  1. Done! The component loads its HomeUrl automatically. To open another page: call WebViewS1.GoToUrl url: "example.com".

:light_bulb: Why a non-visible component? Kodular cannot preview custom visible components without a mock file, so WebViewS is attached to any arrangement via SetLayout. Bonus: you control size and visibility through the arrangement itself (e.g. VerticalArrangement1.Visible).

Permissions used

INTERNET, ACCESS_NETWORK_STATE, ACCESS_FINE_LOCATION (only if UsesLocation is on), RECORD_AUDIO (voice search / microphone), CAMERA (camera access), MODIFY_AUDIO_SETTINGS, READ/WRITE_EXTERNAL_STORAGE (downloads). Dangerous permissions are requested from the user at runtime, only when they are really needed.


:brick: Designer properties

Set in the Designer, or change at runtime with the set WebViewS1.Property blocks.

Page & navigation

Property Default Description
HomeUrl https://www.google.com Page loaded at start and by GoHome.
FollowLinks true If false, links inside the page are not followed (the page cannot navigate away by tapping links).
IgnoreSslErrors false If true, pages with invalid SSL certificates still load. Use only for testing.
JavaScriptEnabled true Turns JavaScript in pages on/off. Many blocks (JSON from JS, element tools, long-press menu for video, dark mode…) need JS on.
UsesLocation false Allows pages to use the device location (navigator.geolocation).
AcceptThirdPartyCookies true Allow or block third-party cookies.
BlockImages false Don’t load images from the network (saves data).
UserAgent (empty) Custom user-agent. Empty = default.
DesktopMode false Desktop version of sites: desktop user-agent + wide viewport. The current page reloads.
DarkMode false Dark theme for web pages (page colors are inverted; images/videos stay normal).

Zoom & text

Property Default Description
ZoomEnabled true Pinch-to-zoom on/off.
DisplayZoom false Show on-screen zoom (+/−) buttons.
TextZoom 100 Font size of pages in percent (100 = normal).

Downloads, pull-to-refresh & long-press menu

Property Default Description
AutoDownload true true: files are downloaded automatically to the Download folder. false: nothing is downloaded, only the DownloadRequested event fires — you decide.
PullToRefreshEnabled true Swipe down at the top of the page to reload.
ContextMenuEnabled true Long-press menu for links, images, video and audio.
NewWindowOpensBrowser true “Open in new window” opens the phone’s browser. If false, only NewWindowRequested is raised so you can open the address in your own screen.

Search bar

Property Default Description
SearchBarVisible true Show/hide the address & search bar.
SearchBarHint Search or enter address Hint text of the empty bar.
SearchBarColor #F1F3F4 Background color of the bar.
SearchBarTextColor #202124 Text color of the bar.
SearchEngineUrl https://www.google.com/search?q= Search prefix; the typed text is appended. Example: https://duckduckgo.com/?q=
AutoLoadOnSubmit true Load the page automatically when the user presses Go/Enter. If false, only SearchSubmitted fires.
AutoSearchAfterVoice true Submit the search right after voice input.
VoiceLanguage (empty) Language tag for voice recognition, e.g. en-US, ru-RU. Empty = phone language.
VoicePrompt Speak now Text shown in the voice recognition dialog.
ProgressBarVisible true Thin loading progress bar under the search bar.

Camera, microphone & ad blocking

Property Default Description
AllowCamera false Lets web pages use the camera (video calls, QR scanners…). Android asks the user for permission.
AllowMicrophone false Lets web pages use the microphone. Android asks the user for permission.
AdBlockEnabled false Blocks requests to advertising and tracking domains.
UseBuiltInBlockList true Use the built-in list (~30 popular ad/tracker domains).
BlockedDomains (empty) Your own domains, separated by comma, space or new line, e.g. ads.example.com, tracker.site.net. Subdomains are blocked too.

:locked: Camera and microphone are off by default so a page can never use them unless you allow it.


:open_book: Read-only properties (get blocks)

Property Returns
CurrentUrl URL of the page currently shown.
CurrentPageTitle Title of the current page.
Progress Loading progress 0–100.
ScrollY Vertical scroll position in pixels.
BlockedRequestCount How many ad/tracker requests were blocked.
PageSource Last page source received by GetPageSource / ShowSource.
SourceViewActive true while the source viewer is shown.
WebViewString (get/set) A string shared with the page (see JavaScript bridge).
SearchText (get/set) Text currently in the search bar; you can also set it.

:wrench: Blocks (methods)

Layout

Block Description
SetLayout(layout) Puts the browser inside the given Horizontal/VerticalArrangement. Call it once in Screen.Initialize.

Navigation

Block Description
GoToUrl(url) Opens the address. https:// is added automatically if missing.
GoHome() Opens HomeUrl.
GoBack() / GoForward() History navigation.
CanGoBack() / CanGoForward() Returns true/false — use it to enable/disable your buttons or handle the phone Back key.
Reload() Reloads the page.
StopLoading() Stops loading.
PostUrl(url, data) Sends an HTTP POST (application/x-www-form-urlencoded), e.g. data user=bob&pass=123.
Search(text) Same as the user pressing Go: opens an address or searches the text with the search engine.
FocusSearchBar() Puts the cursor in the search bar and shows the keyboard.
StartVoiceSearch() Opens voice recognition; the result goes to the search bar and to VoiceSearchResult.

Loading your own content

Block Description
LoadHtml(html) Shows an HTML string as a page. Scripts inside run if JavaScript is enabled.
LoadHtmlWithBaseUrl(html, baseUrl) Same, but as if the page came from baseUrl, so relative links, cookies and requests to that site work.
LoadAsset(fileName) Loads a file from the app’s assets, e.g. index.html.

Find in page

Block Description
FindInPage(text) Highlights all matches. Event FindResult gives the count.
FindNext(forward) Jumps to next (true) or previous (false) match.
ClearFind() Removes the highlights.

Zoom & font size

Block Description
ZoomIn() / ZoomOut() Page zoom; returns true if the zoom changed.
SetFontSize(percent) Font size in percent (100 = normal).
IncreaseFontSize() / DecreaseFontSize() Change font size by 10 points per call.
ResetFontSize() Back to 100%.

JavaScript

Block Description
RunJavaScript(script) Runs JS in the current page. The returned value arrives in AfterJsEvaluated / JavaScriptResult.
RunJavaScriptWithId(id, script) Same, but the result comes in JavaScriptResult with your id — handy when several scripts run at once.
AddScriptOnPageLoad(script) Registers a script that runs automatically every time a page finishes loading.
ClearScriptsOnPageLoad() Removes all registered scripts.
InjectCss(css) Adds a CSS style sheet to the current page, e.g. body{background:#000}.

Page control without JavaScript (CSS selectors)

Use any CSS selector: #id, .class, tag, input[name=email], form button.submit…

Block Result event Description
GetPageText() PageTextReceived(text) Visible text of the page, without HTML.
GetElementText(selector) ElementTextReceived(selector, text, found) Text (or value) of the first matching element.
ClickElement(selector) ElementActionResult("click", selector, success) Scrolls to the element and clicks it.
FillInput(selector, text) ElementActionResult("fill", selector, success) Types text into an input/textarea. Works with modern sites (React/Vue see it as real typing).
ScrollToElement(selector) ElementActionResult("scroll", selector, success) Smoothly scrolls to the element.
ScrollToTop() / ScrollToBottom() – Jump to the top / bottom of the page.

success / found is false when no element matched the selector.

:puzzle_piece: JSON tools

Everything that returns JSON text (AfterJsEvaluated, web APIs, files…) can be used directly.

Block Returns Description
JsonDecode(json) any JSON array → list, JSON object → dictionary, other values → text / number / true-false. Invalid JSON → empty text.
JsonGet(json, path) any One value by path: user.name, items[0].title, data.list[2][1]. Objects/arrays come back as dictionary/list. Not found → empty text.
JsonPluck(json, path, field) list Takes one field from every object of an array. Path users + field name → list of all names. Empty path = the whole JSON is the array.
JsonKeys(json, path) list Keys of the object at the path.
JsonLength(json, path) number Number of items in the array (or keys in the object).
JsonIsValid(json) boolean Is the text a valid JSON object/array?
JsonEncode(value) text List / dictionary / text / number → JSON text.
JsonPretty(json) text Nicely indented JSON, great for debugging or showing in a label.

:warning: Path indexes start from 0 (like in JavaScript): items[0] is the first item. Kodular list blocks start from 1 — don’t mix them up!

Cookies

Block Description
GetCookies(url) All cookies of the URL as one text (a=1; b=2).
GetCookie(url, name) Value of one cookie (empty if none).
SetCookie(url, cookie) Sets a cookie, e.g. token=abc123; path=/.
DeleteCookie(url, name) Deletes one cookie.
ClearCookies() Removes all cookies.

Cleaning

Block Description
ClearCaches() Clears the WebView cache.
ClearHistory() Clears navigation history.
ClearWebStorage() Clears localStorage / WebSQL / IndexedDB of all sites.
ClearLocations() Clears location permissions given to pages.

Page source

Block Description
GetPageSource() HTML of the page as the browser sees it (after scripts ran) → event GotPageSource.
FetchRawSource(url) Downloads the original HTML from the network (no scripts executed, cookies included). Empty url = current page. → RawSourceReceived or RawSourceFailed.
ShowSource() Shows the source code inside the component (like view-source).
HideSource() Returns to the normal page.

Files, screenshot, PDF

Block Description
DownloadFile(url) Downloads a file to the Download folder (works even if AutoDownload is off).
TakeScreenshot(fileName) Saves a PNG of the visible part of the page to Pictures/WebViewS. FileName may be empty. → ScreenshotSaved(uri).
SavePageAsPdf(jobName) Opens the Android print dialog — choose “Save as PDF” there.

Ad blocking

Block Description
AddBlockedDomain(domain) Adds a domain to your list (you can paste a full URL — the host is extracted; *.site.com is accepted). Subdomains are blocked too.
RemoveBlockedDomain(domain) Removes a domain from your list.
ClearBlockedDomains() Clears your list (the built-in list stays).
ResetBlockedRequestCount() Resets the counter.

Only sub-resources (ads, trackers, scripts, images) are blocked — the page you open yourself is never blocked.


:bell: Events

Page lifecycle

Event When it fires
PageStarted(url) A page started loading.
PageLoaded(url) A page finished loading.
ProgressChanged(progress) Progress 0–100 changed.
ReceivedTitle(title) The page title became known.
ErrorOccurred(errorCode, description, failingUrl) Loading failed, a download failed, JS is disabled, etc.

JavaScript

Event When it fires
AfterJsEvaluated(result) After any RunJavaScript / RunJavaScriptWithId finished. Strings come without quotes; objects/arrays as JSON text → pass to JsonDecode.
JavaScriptResult(id, result) Result together with the id you passed (id is empty for RunJavaScript).
ConsoleMessageReceived(message, lineNumber, level) The page called console.log etc. Level: LOG, WARNING, ERROR, TIP, DEBUG. Great for debugging.
JsMessage(message) The page called AppInventor.sendToApp(text).
WebViewStringChange(value) The page called AppInventor.setWebViewString(text).

Page tools

Event When it fires
PageTextReceived(text) Result of GetPageText.
ElementTextReceived(selector, text, found) Result of GetElementText.
ElementActionResult(action, selector, success) Result of ClickElement / FillInput / ScrollToElement. action = click, fill or scroll.
GotPageSource(html) Result of GetPageSource.
RawSourceReceived(url, source) / RawSourceFailed(url, error) Result of FetchRawSource.
FindResult(activeMatch, totalMatches) Result of FindInPage.
ScreenshotSaved(uri) Screenshot file was created.

Scrolling

Event When it fires
OnScrollChanged(y) The page scrolled; y = position in pixels.
OnScrolledToBottom() The user reached the bottom. Fires again after the page grows (infinite scroll) and the user reaches the new bottom.

User actions

Event When it fires
DownloadRequested(url, userAgent, contentDisposition, mimeType, contentLength) The page wants to download a file (fires even when AutoDownload is on).
NewWindowRequested(url) The user chose Open in new window in the long-press menu.
SearchSubmitted(text) The user pressed Go/Enter in the search bar.
VoiceSearchResult(text) / VoiceSearchError(message) Voice recognition finished / failed.

:link: JavaScript bridge (page ⇄ app)

Your own web pages (loaded with LoadHtml, LoadAsset or from a server) can talk to the app through the global object window.AppInventor:

// send a message to the app  →  event JsMessage(message)
AppInventor.sendToApp("button clicked");

// store a string for the app  →  event WebViewStringChange(value)
AppInventor.setWebViewString("hello from page");

// read the string that the app put into WebViewString
var s = AppInventor.getWebViewString();

In blocks: set WebViewS1.WebViewString to "token123" — the page can read it with getWebViewString().


:backhand_index_pointing_up: Long-press menu (like Chrome)

You long-press… The menu offers
Link Open link · Open in new window · Copy link address · Download link · Share link
Image Open image in new window · Download image · Copy image address · Share image (if the image is also a link, link items are added too)
Video / Audio Open in new window · Download · Copy address · Share
Text The normal Android text selection with Copy / Select all / Share

The menu language follows the phone (Russian or English). “Open in new window” raises NewWindowRequested(url) and, by default, opens the phone’s browser — switch this off with NewWindowOpensBrowser = false if you want to handle it yourself (for example, open the address in a second screen with another WebViewS).


:cooking: Recipes (copy & paste ideas)

1) Read a JSON API value from a page

call WebViewS1.RunJavaScript  script: "JSON.stringify(window.products)"

when WebViewS1.AfterJsEvaluated(result)
do  set ListView1.Elements to  call WebViewS1.JsonPluck(json: result, path: "", field: "title")

→ a ListView with the title of every product.

2) Auto-login

when WebViewS1.PageLoaded(url)
do  call WebViewS1.FillInput  selector: "input[name=email]"  text: "me@mail.com"
    call WebViewS1.FillInput  selector: "input[type=password]" text: "secret"
    call WebViewS1.ClickElement selector: "button[type=submit]"

3) Scrape the price of a product

call WebViewS1.GetElementText  selector: ".price"

when WebViewS1.ElementTextReceived(selector, text, found)
do  if found then set Label1.Text to text

4) Infinite scroll / “load more”

when WebViewS1.OnScrolledToBottom
do  call WebViewS1.ClickElement  selector: "#load-more"

5) Dark mode switch

when Switch1.Changed
do  set WebViewS1.DarkMode to Switch1.On

6) Remove annoying elements from every page

call WebViewS1.AddScriptOnPageLoad  script: "document.querySelectorAll('.cookie-banner,.popup').forEach(e=>e.remove())"

7) Keep the login between app starts

when WebViewS1.PageLoaded(url)
do  set TinyDB1 "session" to  call WebViewS1.GetCookie(url, "session")

when Screen1.Initialize
do  call WebViewS1.SetCookie  url: "https://site.com"  cookie: "session=" + TinyDB1.GetValue("session")

8) Handle the Back key

when Screen1.BackPressed
do  if call WebViewS1.CanGoBack  then call WebViewS1.GoBack  else close application

:warning: Good to know

  • JavaScript must be enabled (JavaScriptEnabled) for: JS blocks, JSON-from-page workflows, element tools, dark mode, desktop viewport, long-press menu on video/audio.
  • Results are asynchronous. A WebView answers later, so blocks like GetPageText or GetElementText deliver their data in an event, not as a return value (a blocking “wait for result” block would freeze the app).
  • Downloads: blob: links (e.g. YouTube video) cannot be downloaded or opened externally — you can only copy their address. data: images are saved to the Download folder when the Android version allows it.
  • Dark mode inverts colors, so a page that is already dark becomes light — switch it off for such sites.
  • Screenshot captures the visible part of the page. PDF uses the system print dialog.
  • Ad blocking works on domain level; it will not remove ads served from the same domain as the content.
  • Camera and microphone for pages require both the property (AllowCamera / AllowMicrophone) and the user’s permission in Android.
  • Add SetLayout only once and as early as possible (Screen.Initialize).

:hammer_and_wrench: Troubleshooting

Problem Solution
Nothing is shown Did you call SetLayout? Is the arrangement Fill parent (width and height) and visible?
A page doesn’t work / is blank Check JavaScriptEnabled, try DesktopMode, watch ErrorOccurred and ConsoleMessageReceived.
ElementActionResult says success = false The element isn’t there yet — run the block in PageLoaded or after a short Clock delay (modern sites render late).
Camera in a web page doesn’t start Turn on AllowCamera, accept the Android permission, and use an https:// page (browsers require it).
Download doesn’t start Check AutoDownload, and watch ErrorOccurred (some links are blob:).

com.webviews.aix (97.8 KB)

The extension was created with the help of: :rocket: FAST

3 Likes

:rocket: WebViewS update: background playback and background HTTP requests

Your app can now keep working when it is minimized, when the screen is locked, and even after the user swipes it away from recent apps. This update adds two big features:

Feature In one sentence
:headphone: Background playback Music and video from any website keep playing, with a real media player in the notification shade and on the lock screen.
:globe_with_meridians: Background HTTP requests Send GET / POST / JSON / form requests without freezing the app, repeat them every N seconds in the background, and get a notification when the answer changes.

Both features use Android foreground services, so the system treats them as visible, user-approved work and is far less likely to kill them.


1) Quick start

Background playback (2 steps)

  1. In the Designer set BackgroundPlayback = true on WebViewS.
  2. Open a site with audio or video and start playing. Minimize the app or lock the screen.

That’s it. A media notification appears automatically. No extra blocks needed.

Background HTTP (1 block)

call WebViewS1.HttpGet  id: "test"  url: "https://api.example.com/data"  headers: ""

when WebViewS1.HttpResponse(id, statusCode, body, responseHeaders, success, late)
do  set Label1.Text to body

2) :headphone: Background playback

What the user sees

  • A media notification with cover art, title, artist, buttons :last_track_button: :play_or_pause_button: :next_track_button:, a ✕ Stop button and a progress bar.
  • The same player on the lock screen (and in Quick Settings on Android 13+). Headset buttons work too.
  • When the app is opened again, the same page is still there and still playing. It is not reloaded.

When it starts and stops

Situation What happens
App is open Nothing is shown yet. The page plays normally.
App minimized / screen locked while media plays The service starts and the notification appears.
App swiped away from recent apps while media plays The service keeps running and the page keeps playing.
User taps ✕ Stop Media is paused, the service stops, the notification disappears.
Nothing is playing for 30 seconds, or media stays paused for 10 minutes The service stops by itself (reason idle).

How it works (short)

  • A foreground media service with a MediaSession (the system player UI).
  • A CPU and Wi-Fi wake lock while the service runs, so audio does not stop with the screen off.
  • The page is kept “visible” for the site’s scripts, so sites do not pause themselves when the screen turns off.
  • The WebView is kept alive in the app process after the screen is closed.
  • Title, artist and cover come from the site’s own media info (navigator.mediaSession). If a site gives none, the page title is used.

Property

Property Default Description
BackgroundPlayback false Turns the whole feature on or off. When on, the service starts automatically as soon as the app goes to the background while media is playing.

Blocks

Block What it does and when to use it
StartBackgroundPlayback() Starts the service right now (notification + lock screen player). Use it if you want the player to appear before the user leaves the app.
StopBackgroundPlayback() Stops the service and removes the notification.
MediaPlay() Plays the audio/video of the page. Use it for your own play button.
MediaPause() Pauses it.
MediaNext() Next track. Uses the site’s own media session or its Next button. If the site has none, it jumps to the end of the current track.
MediaPrevious() Previous track, with the same fallbacks (jumps to the start of the track).
MediaSeekTo(seconds) Jumps to a position, in seconds. Use it with a Slider to build your own progress bar.

Read-only properties (get blocks)

Property Returns
BackgroundPlaybackActive true while the service and notification are running.
MediaPlaying true while the page plays audio or video.
MediaTitle Title of the current media.
MediaArtist Artist of the current media.
MediaPosition Current position in seconds.
MediaDuration Length in seconds (0 for live streams).

Events

Event When it fires
MediaInfoChanged(title, artist, album, artworkUrl, playing) A new track started, or play/pause changed. Use it to update your own player UI.
BackgroundPlaybackStarted() The service started.
BackgroundPlaybackStopped(reason) The service stopped. reason is user (Stop button or block), idle (nothing played for a long time) or system (Android stopped it).

Example: your own player UI + background playback

when Screen1.Initialize
do  call WebViewS1.SetLayout  layout: VerticalArrangement1
    set WebViewS1.BackgroundPlayback to true

when WebViewS1.MediaInfoChanged(title, artist, album, artworkUrl, playing)
do  set Label1.Text to  join(title, " - ", artist)
    set Button1.Text to  if playing then "Pause" else "Play"

when Button1.Click
do  if WebViewS1.MediaPlaying
    then call WebViewS1.MediaPause
    else call WebViewS1.MediaPlay

when Slider1.PositionChanged(thumbPosition)
do  call WebViewS1.MediaSeekTo  seconds: thumbPosition

Good to know

  • Works with one WebViewS per app.
  • Android 13+ asks for the notification permission once. Without it playback still works, but the notification is hidden.
  • Big sites (YouTube, YouTube Music, SoundCloud and similar) usually provide title, cover and next/previous. Simple pages fall back to the page title.
  • Some sites block background play for non-premium users, and DRM-protected streams cannot be played by Android WebView at all.
  • Combine with DesktopMode for sites whose mobile version refuses to play in the background.
  • Some phone makers (Xiaomi, Huawei, Oppo, Samsung power saving) kill background apps. If playback stops after a few minutes, set the app’s battery mode to No restrictions.

3) :globe_with_meridians: Background HTTP requests

Use these blocks when you only need data (an API, a status page, a login check) and not a visible page.

Common rules

  • Requests run in background threads. The app never freezes.
  • id is your own name for the request. It comes back in the event, so you can tell several requests apart.
  • headers can be a dictionary, JSON text, or lines like Authorization: Bearer abc (one per line). Leave it empty for none.
  • Cookies are shared with the WebView: log in once in the browser, and background requests are logged in too.
  • The answer is limited to 5 MB of text.

Properties

Property Default Description
HttpTimeout 30 Timeout of background requests, in seconds.
HttpUseWebViewCookies true Send the WebView cookies and save the cookies the server sets.

One-time request blocks

Block What it does
HttpGet(id, url, headers) GET request.
HttpPost(id, url, body, headers) POST with a text body.
HttpPostJson(id, url, json, headers) POST with JSON. json can be JSON text or a dictionary/list (converted for you, no manual JSON needed).
HttpPostForm(id, url, fields, headers) POST like an HTML form. fields can be a dictionary or text like a=1&b=2.
HttpRequest(id, method, url, headers, body) Any method: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.

Periodic (repeating) request blocks

Block What it does
StartBackgroundRequest(id, method, url, headers, body, intervalSeconds) Repeats the request every N seconds (minimum 10). Runs while the app is minimized or closed. A small notification “Background requests running” with a Stop button is shown. Using the same id again replaces the old request.
StopBackgroundRequest(id) Stops one periodic request.
StopAllBackgroundRequests() Stops all of them and removes the notification.

Alerts and late results

Block What it does
SetBackgroundAlert(id, mode, text, title) Shows an Android notification for that request, even when the app is closed. Modes: change (the answer changed), contains (the answer now contains text), always (every answer), off. title may be empty.
DeliverPendingResults() Delivers answers that arrived while the app was closed. It also happens automatically when the app opens.
ClearPendingResults() Forgets those answers.
RequestIgnoreBatteryOptimizations() Opens the Android dialog that lets the app run without battery limits. Recommended for reliable timing with the screen off.

Read-only properties

Property Returns
BackgroundRequestIds List of ids of the periodic requests that are running.
BackgroundRequestsRunning true while at least one periodic request runs.
PendingResultCount How many answers are waiting to be delivered (they arrived while the app was closed).

Events

Event When it fires
HttpResponse(id, statusCode, body, responseHeaders, success, late) A request got an answer. success is true for codes 200-299. Codes like 404 and 500 also arrive here, with success = false. responseHeaders is JSON text (use JsonDecode / JsonGet). late is true if the answer arrived while the app was closed.
HttpFailed(id, error, late) No network, timeout, or a bad address.

Examples

Read a value from an API

call WebViewS1.HttpGet  id: "weather"  url: "https://api.example.com/today"  headers: ""

when WebViewS1.HttpResponse(id, statusCode, body, responseHeaders, success, late)
do  if id = "weather" and success
    then set Label1.Text to  call WebViewS1.JsonGet(body, "current.temp")

Log in with a dictionary

call WebViewS1.HttpPostJson  id: "login"  url: "https://site.com/api/login"
     json: (dictionary: email = "me@mail.com", password = "secret")  headers: ""

Send a token in the headers

call WebViewS1.HttpGet  id: "profile"  url: "https://site.com/api/me"
     headers: "Authorization: Bearer YOUR_TOKEN"

Watch a price while the app is closed

call WebViewS1.StartBackgroundRequest  id: "price"  method: "GET"
     url: "https://shop.com/api/item/42"  headers: ""  body: ""  intervalSeconds: 60
call WebViewS1.SetBackgroundAlert  id: "price"  mode: "change"  text: ""  title: "Price changed!"

Every minute the app asks the server. When the answer changes, Android shows a notification, even if the app was swiped away. When the user opens the app later, all answers that arrived meanwhile are delivered to HttpResponse with late = true.

Get notified when a word appears

call WebViewS1.StartBackgroundRequest  id: "tickets"  method: "GET"
     url: "https://event.com/status"  headers: ""  body: ""  intervalSeconds: 120
call WebViewS1.SetBackgroundAlert  id: "tickets"  mode: "contains"  text: "Available"  title: "Tickets are on sale"

The notification fires once when the word appears (not on every check).

Read the response headers

when WebViewS1.HttpResponse(id, statusCode, body, responseHeaders, success, late)
do  set Label1.Text to  call WebViewS1.JsonGet(responseHeaders, "content-type")

(Header names are lowercase.)

Good to know

  • Periodic requests need a foreground service, so Android shows a small notification. On Android 13+ the user is asked for the notification permission once.
  • They keep running while the app is minimized or swiped away, but stop if the phone force-stops the app or kills the process. They are not restarted after a reboot.
  • With the screen off for a long time, Android Doze mode may delay requests. Use RequestIgnoreBatteryOptimizations for reliable timing.
  • Android 15 limits “data sync” foreground services to about 6 hours per day. After that the requests stop.
  • Late results: up to 50 are stored, each body cut to 100,000 characters.
  • Events are delivered while the app is minimized. They are stored only when the app is fully closed.

4) Permissions added by this update

You do not need to add these yourself: they are in the extension manifest and merged into your app.

Permission Why
FOREGROUND_SERVICE Run the playback and request services.
FOREGROUND_SERVICE_MEDIA_PLAYBACK Media service type (Android 14+).
FOREGROUND_SERVICE_DATA_SYNC Background requests service type (Android 14+).
WAKE_LOCK Keep the CPU awake while playing or polling.
ACCESS_WIFI_STATE Wi-Fi lock for smooth streaming.
POST_NOTIFICATIONS Show notifications on Android 13+ (asked at runtime).
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Used only by RequestIgnoreBatteryOptimizations.

5) Troubleshooting

Problem Solution
No notification appears On Android 13+ allow notifications for the app. Check that BackgroundPlayback is on and that media is really playing when you leave the app.
Music stops after a few minutes with the screen off Set the app’s battery mode to No restrictions (or call RequestIgnoreBatteryOptimizations).
Title or cover is missing The site does not provide media info. The page title is used instead.
Next does nothing useful The site has no media session and no recognizable Next button. The extension then jumps to the end of the track.
HttpResponse never fires Check HttpFailed for the error text, the address (https://) and HttpTimeout.
Periodic requests stopped The service was stopped (Stop button, force-stop, process killed, or the Android 15 time limit). Start them again.
Late results do not arrive They arrive when the app is opened again (or call DeliverPendingResults). Check PendingResultCount.

6) Changelog

Added

  • Property: BackgroundPlayback, HttpTimeout, HttpUseWebViewCookies
  • Blocks: StartBackgroundPlayback, StopBackgroundPlayback, MediaPlay, MediaPause, MediaNext, MediaPrevious, MediaSeekTo, HttpGet, HttpPost, HttpPostJson, HttpPostForm, HttpRequest, StartBackgroundRequest, StopBackgroundRequest, StopAllBackgroundRequests, SetBackgroundAlert, DeliverPendingResults, ClearPendingResults, RequestIgnoreBatteryOptimizations
  • Read-only properties: BackgroundPlaybackActive, MediaPlaying, MediaTitle, MediaArtist, MediaPosition, MediaDuration, BackgroundRequestIds, BackgroundRequestsRunning, PendingResultCount
  • Events: MediaInfoChanged, BackgroundPlaybackStarted, BackgroundPlaybackStopped, HttpResponse, HttpFailed

Questions or bugs? Reply in this thread with your Kodular version, what you did, and a screenshot of your blocks. Happy building! :headphone::globe_with_meridians:


com.webviews.aix (145.9 KB)