About WebMonkey
WebMonkey No-frills light-weight Android web browser with support for Greasemonkey userscripts. Builds upon the WebView GM library demo application. Background the WebView GM library enhances the native Android System WebView with userscript management: detecting and downloading *.user.js URLs parsing and saving to a DB automatic updates with userscript injection: on top-level HTML pages that match URL patterns with support for Greasemonkey API ( 1 , 2 , 3 ) functions: GM_addStyle GM_deleteValue GM_getResourceText GM_getResourceURL GM_getValue GM_listValues GM_log GM_setValue GM_xmlhttpRequest Improvements supplements the list of supported Greasemonkey API functions: legacy: GM_addElement GM_cookie.delete GM_cookie.list GM_cookie.set GM_download where the url (or details.url ) parameter accepts any of the following data types: String containing a valid URI having any of the following protocols: http: https: data: ArrayBuffer Uint8Array only works on devices running API 19 (Android 4.4 KitKat) and higher requires SAF GM_fetch drop-in replacement for window.fetch that uses GM_xmlhttpRequest to make network requests GM_info GM_registerMenuCommand GM_unregisterMenuCommand GM 4 : GM.addElement GM.addStyle GM.cookie.delete GM.cookie.list GM.cookie.set GM.cookies.delete GM.cookies.list GM.cookies.set GM.deleteValue GM.download GM.fetch GM.getResourceText GM.getResourceUrl GM.getValue GM.info GM.listValues GM.log GM.registerMenuCommand GM.setValue GM.unregisterMenuCommand GM.xmlHttpRequest adds an additional Javascript API interface to expose Android-specific capabilities: legacy: GM_exit() causes WebMonkey to close GM_getUrl() returns a String containing the URL that is currently loaded in the WebView use case: allows the userscript to detect whether the page has been redirected server response status codes: 301, 302 example: var is_redirect = (GM_getUrl() !== unsafeWindow.location.href) GM_getUserAgent() returns a String containing the User Agent that is currently configured in Settings for use by the WebView GM_loadFrame(urlFrame, urlParent, proxyFrame) loads an iframe into the WebView where: [required] urlFrame is a String URL: the page loaded into the iframe [required] urlParent is a String URL: value for window.top.location.href and window.parent.location.href as observed from within the iframe [optional] proxyFrame is a boolean: a truthy value causes urlFrame to be downloaded in Java urlParent is sent in the Referer header a successful (200-299) response is dynamically loaded into iframe.srcdoc the benefit: same-origin policy does not apply when urlParent and urlFrame belong to different domains, a userscript running in the top window can access the DOM within the iframe window special use case: when urlFrame only serves the desired web page content if urlParent is sent in the Referer header example: (' example.com/iframe_window.html' , ' example.com/parent_window.html' ) use case: "parent_window.html" contains: an iframe to display "iframe_window.html" other content that is not wanted though a userscript could easily do the necessary housekeeping: detach the iframe remove all other DOM elements from body reattach the iframe this method provides a better solution: removes all scripts that are loaded into the parent window handles all the css needed to resize the iframe to maximize its display within the parent window makes it easy to handle this common case why this is a common case: "iframe_window.html" performs a check to verify that it is loaded in the proper parent window example 1: const urlParent = ' example.com/parent_window.html' try { // will throw when either: // - `top` is loaded from a different domain // - `top` is loaded from the same origin, but the URL path does not match 'parent_window.html' if ( window . top . location . href !== urlParent ) throw '' } catch ( e ) { // will redirect `top` window to the proper parent window window . top . location = urlParent } example 2: const urlParent = ' example.com/parent_window.html' { // will redirect to proper parent window when 'iframe_window.html' is loaded without a `top` window if ( window === window . top ) window . location = urlParent } GM_loadUrl(url, ...headers) loads a URL into the WebView with additional HTTP request headers where: [required] url is a String URL [optional] headers is a list of String name/value pairs example: (' example.com/iframe_window.html' , 'Referer', ' example.com/parent_window.html' ) GM_removeAllCookies() completely removes all cookies for all web sites GM_resolveUrl(urlRelative, urlBase) returns a String containing urlRelative resolved relative to urlBase where: [required] urlRelative is a String URL: relative path [optional] urlBase is a String URL: absolute path default value: the URL that is currently loaded in the WebView examples: ('video.mp4', ' example.com/iframe_window.html' ) ('video.mp4') GM_setUserAgent(value) changes the User Agent value that is configured in Settings where: [optional] value is a String special cases: WebView (or falsy) Chrome GM_startIntent(action, data, type, ...extras) starts an implicit Intent where: [required, can be empty] action is a String [required, can be empty] data is a String URL [required, can be empty] type is a String mime-type for format of data [optional] extras is a list of String name/value pairs example: ('android.intent.action.VIEW', ' example.com/video.mp4' , 'video/mp4', 'referUrl', ' example.com/videos.html' ) GM_toastLong(message) GM_toastShort(message) GM 4 : GM.exit GM.getUrl GM.getUserAgent GM.loadFrame GM.loadUrl GM.removeAllCookies GM.resolveUrl GM.setUserAgent GM.startIntent GM.toastLong GM.toastShort Settings default browser home page Continue where you left off Blank page Userscripts by developer Userscripts at Greasy Fork Custom URL User Agent WebView Chrome desktop Custom User Agent implementation for @run-at document-end document: DOMContentLoaded WebViewClient: onPageFinished this option can cause userscripts to run more than once per page load issue discussion utility: WebViewClient event observer page load behavior on HTTPS certificate error cancel proceed ask script update interval number of days to wait between checks special case: 0 disables automatic script updates shared secret for JS to access low-level API method: window . WebViewWM . getUserscriptJS ( secret , url ) specific use case: mitmproxy script to inject JS code to bootstrap userscripts in iframes enable remote debugger allows remote access over an adb connection, such as: adb connect " ${IP_of_phone_on_LAN} :5555 " remote debugger is accessible in Chrome at: chrome://inspect/#devices the interface uses Chrome DevTools AdBlock Settings enable AdBlock default: true custom Blocklist URL default: pgl.yoyo.org note: if this URL is empty or cannot be downloaded, a static copy of the default blocklist that is included in the app will be used custom Blocklist update interval number of days to wait before downloading a fresh copy of the blocklist default: 7 Security closure by default, all JS code injected into web pages is wrapped by a closure the closure is implemented as a self-executing anonymous function , also known as an immediately invoked function expression this security feature can be disabled by a userscript by adding any of the following declarations to its header block: // @unwrap // @flag noJsClosure // @flags noJsClosure SANDBOX.txt contains more details sandbox when a closure is disabled, a sandbox is also disabled when a closure is enabled, by default, all JS global variables saved to the window Object are stored in a sandbox as such, JS code outside of the userscript cannot see or access these variables however, the JS code inside of the userscript can see and access all global variables… including its own the sandbox is implemented as an ES6 Proxy this security feature can be disabled by a userscript by adding any of the following declarations to its header block: // @grant none // @flag noJsSandbox // @flags noJsSandbox SANDBOX.txt contains more details API-level permissions // @grant is only required to use API methods that I would consider to be potentially dangerous several of these API methods are grouped together, and permission granted for any one… also grants permission to use all other API methods in the same group group: GM_setValue GM_getValue GM_deleteValue GM_listValues GM.setValue GM.getValue GM.deleteValue GM.listValues group: GM_cookie GM_cookie.list GM_cookie.set GM_cookie.delete GM.cookie GM.cookie.list GM.cookie.set GM.cookie.delete GM.cookies GM.cookies.list GM.cookies.set GM.cookies.delete group: GM_removeAllCookies GM.removeAllCookies group: GM_setUserAgent GM.setUserAgent Caveats userscripts only run in the top window a mitmproxy script is required to load userscripts into iframes Legal: copyright: Warren Bank license: GPL-2.0