Files
Android-pyApi/android_pyapi/android/webkit_ext.py
T
shuiyu1123 a51854455b feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等)
- java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等)
- javax/ 4个模块 (net/crypto/security/sql)
- org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http)
- dalvik/ 1个模块 (system)
- ~3053个类/接口,方法签名完全对齐Android SDK
- 桌面跨平台运行 (Windows/macOS/Linux)
- 修复所有导入错误和Python关键字冲突
2026-06-24 14:15:56 +00:00

1554 lines
48 KiB
Python

"""
Android WebKit 扩展组件 — WebView, WebSettings, WebViewClient, WebChromeClient 等
方法签名完全对齐 Android SDK
"""
from __future__ import annotations
import os
import json
import threading
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
from .._core import Stub, AndroidOnlyError
from ..java.lang import RuntimeException
# ═══════════════════════════════════════════════════════════════
# WebView 常量
# ═══════════════════════════════════════════════════════════════
LOAD_DEFAULT = 0
LOAD_CACHE_ONLY = 1
LOAD_CACHE_ELSE_NETWORK = 2
LOAD_NO_CACHE = 3
LOAD_NORMAL = 0
ERROR_UNKNOWN = -1
ERROR_HOST_LOOKUP = -2
ERROR_UNSUPPORTED_AUTH_SCHEME = -3
ERROR_AUTHENTICATION = -4
ERROR_PROXY_AUTHENTICATION = -5
ERROR_CONNECT = -6
ERROR_IO = -7
ERROR_TIMEOUT = -8
ERROR_REDIRECT_LOOP = -9
ERROR_UNSUPPORTED_SCHEME = -10
ERROR_FAILED_SSL_HANDSHAKE = -11
ERROR_BAD_URL = -12
ERROR_FILE = -13
ERROR_FILE_NOT_FOUND = -14
ERROR_TOO_MANY_REQUESTS = -15
NAVIGATION_TYPE_LINK_CLICKED = 0
NAVIGATION_TYPE_FORM_SUBMITTED = 1
NAVIGATION_TYPE_BACK_FORWARD = 2
NAVIGATION_TYPE_RELOAD = 3
NAVIGATION_TYPE_FORM_RESUBMITTED = 4
NAVIGATION_TYPE_OTHER = -1
OVER_SCROLL_NEVER = 2
OVER_SCROLL_ALWAYS = 0
OVER_SCROLL_IF_CONTENT_SCROLLS = 1
RENDERER_PRIORITY_WAIVED = 0
RENDERER_PRIORITY_BOUND = 1
RENDERER_PRIORITY_IMPORTANT = 2
SCHEME_HTTP = "http"
SCHEME_HTTPS = "https"
SCHEME_FILE = "file"
SCHEME_ABOUT = "about"
SCHEME_DATA = "data"
SCHEME_JAVASCRIPT = "javascript"
WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER = 1
WEB_CHROME_CLIENT_GET_VISITED_HISTORY = 2
WEB_RESOURCE_ERROR_STYLE_BOX = 0
WEB_RESOURCE_ERROR_STYLE_GENERIC = 1
# ═══════════════════════════════════════════════════════════════
# WebResourceRequest / WebResourceResponse / WebResourceError
# ═══════════════════════════════════════════════════════════════
class WebResourceRequest(Stub):
"""WebResourceRequest — 资源请求"""
def __init__(self, url: str = "", is_for_main_frame: bool = False,
is_redirect: bool = False, method: str = "GET",
request_headers: Optional[Dict[str, str]] = None,
has_user_gesture: bool = False,
is_main_frame: bool = False):
super().__init__()
self._url = url
self._is_for_main_frame = is_for_main_frame
self._is_redirect = is_redirect
self._method = method
self._request_headers = request_headers or {}
self._has_user_gesture = has_user_gesture
self._is_main_frame = is_main_frame
def getUrl(self) -> str:
return self._url
def isForMainFrame(self) -> bool:
return self._is_for_main_frame
def isRedirect(self) -> bool:
return self._is_redirect
def getMethod(self) -> str:
return self._method
def getRequestHeaders(self) -> Dict[str, str]:
return dict(self._request_headers)
def hasUserGesture(self) -> bool:
return self._has_user_gesture
def isMainFrame(self) -> bool:
return self._is_main_frame
def toString(self) -> str:
return f"WebResourceRequest(url={self._url}, method={self._method})"
class WebResourceResponse(Stub):
"""WebResourceResponse — 资源响应"""
def __init__(self, mime_type: str = "", encoding: str = "",
data: Any = None, status_code: int = 200,
reason_phrase: str = "OK",
response_headers: Optional[Dict[str, str]] = None):
super().__init__()
self._mime_type = mime_type
self._encoding = encoding
self._data = data
self._status_code = status_code
self._reason_phrase = reason_phrase
self._response_headers = response_headers or {}
def getMimeType(self) -> str:
return self._mime_type
def getEncoding(self) -> str:
return self._encoding
def getData(self) -> Any:
return self._data
def getStatusCode(self) -> int:
return self._status_code
def getReasonPhrase(self) -> str:
return self._reason_phrase
def getResponseHeaders(self) -> Dict[str, str]:
return dict(self._response_headers)
def setMimeType(self, mime_type: str) -> None:
self._mime_type = mime_type
def setEncoding(self, encoding: str) -> None:
self._encoding = encoding
def setData(self, data: Any) -> None:
self._data = data
def setStatusCodeAndReasonPhrase(self, status_code: int, reason: str) -> None:
self._status_code = status_code
self._reason_phrase = reason
def setResponseHeaders(self, headers: Dict[str, str]) -> None:
self._response_headers = dict(headers)
def toString(self) -> str:
return (f"WebResourceResponse(status={self._status_code}, "
f"mime={self._mime_type})")
class WebResourceError(Stub):
"""WebResourceError — 资源错误"""
ERROR_UNKNOWN = ERROR_UNKNOWN
ERROR_HOST_LOOKUP = ERROR_HOST_LOOKUP
ERROR_UNSUPPORTED_AUTH_SCHEME = ERROR_UNSUPPORTED_AUTH_SCHEME
ERROR_AUTHENTICATION = ERROR_AUTHENTICATION
ERROR_PROXY_AUTHENTICATION = ERROR_PROXY_AUTHENTICATION
ERROR_CONNECT = ERROR_CONNECT
ERROR_IO = ERROR_IO
ERROR_TIMEOUT = ERROR_TIMEOUT
ERROR_REDIRECT_LOOP = ERROR_REDIRECT_LOOP
ERROR_UNSUPPORTED_SCHEME = ERROR_UNSUPPORTED_SCHEME
ERROR_FAILED_SSL_HANDSHAKE = ERROR_FAILED_SSL_HANDSHAKE
ERROR_BAD_URL = ERROR_BAD_URL
ERROR_FILE = ERROR_FILE
ERROR_FILE_NOT_FOUND = ERROR_FILE_NOT_FOUND
ERROR_TOO_MANY_REQUESTS = ERROR_TOO_MANY_REQUESTS
def __init__(self, error_code: int = ERROR_UNKNOWN, description: str = ""):
super().__init__()
self._error_code = error_code
self._description = description
def getErrorCode(self) -> int:
return self._error_code
def getDescription(self) -> str:
return self._description
def toString(self) -> str:
return f"WebResourceError(code={self._error_code}, desc={self._description})"
# ═══════════════════════════════════════════════════════════════
# WebMessage / WebMessagePort / WebMessageListener
# ═══════════════════════════════════════════════════════════════
class WebMessage(Stub):
"""WebMessage — Web消息"""
def __init__(self, data: str = "", ports: Optional[List["WebMessagePort"]] = None):
super().__init__()
self._data = data
self._ports = list(ports) if ports else []
def getData(self) -> str:
return self._data
def getPorts(self) -> List["WebMessagePort"]:
return list(self._ports)
def toString(self) -> str:
return f"WebMessage(data={self._data[:50]})"
class WebMessagePort(Stub):
"""WebMessagePort — Web消息端口"""
def __init__(self):
super().__init__()
self._callback: Optional[Callable] = None
self._closed = False
def postMessage(self, message: WebMessage) -> None:
if self._closed:
raise RuntimeException("WebMessagePort 已关闭")
if self._callback:
self._callback(message)
def close(self) -> None:
self._closed = True
self._callback = None
def setWebMessageCallback(self, callback: Optional[Callable]) -> None:
self._callback = callback
def isClosed(self) -> bool:
return self._closed
def toString(self) -> str:
return f"WebMessagePort(closed={self._closed})"
class WebMessageListener(Stub):
"""WebMessageListener — Web消息监听器"""
def onPostMessage(self, view: Any, message: WebMessage,
source_origin: str, is_main_frame: bool,
js_ports: List[WebMessagePort]) -> None:
pass
# ═══════════════════════════════════════════════════════════════
# WebStorage
# ═══════════════════════════════════════════════════════════════
class WebStorage(Stub):
"""WebStorage — Web存储"""
class UsageInfo(Stub):
"""WebStorage.UsageInfo — 使用信息"""
def __init__(self, origin: str = "", usage: int = 0, quota: int = 0):
super().__init__()
self._origin = origin
self._usage = usage
self._quota = quota
def getOrigin(self) -> str:
return self._origin
def getUsage(self) -> int:
return self._usage
def getQuota(self) -> int:
return self._quota
def toString(self) -> str:
return f"UsageInfo(origin={self._origin}, usage={self._usage})"
def __init__(self):
super().__init__()
self._storage: Dict[str, int] = {}
self._lock = threading.Lock()
def getOrigins(self, callback: Callable) -> None:
with self._lock:
callback(list(self._storage.keys()))
def getUsageForOrigin(self, origin: str, callback: Callable) -> None:
with self._lock:
callback(self._storage.get(origin, 0))
def getQuotaForOrigin(self, origin: str, callback: Callable) -> None:
with self._lock:
callback(self._storage.get(origin, 5 * 1024 * 1024))
def setQuotaForOrigin(self, origin: str, quota: int) -> None:
with self._lock:
self._storage[origin] = quota
def deleteOrigin(self, origin: str) -> None:
with self._lock:
self._storage.pop(origin, None)
def deleteAllData(self) -> None:
with self._lock:
self._storage.clear()
def toString(self) -> str:
return f"WebStorage(origins={len(self._storage)})"
# ═══════════════════════════════════════════════════════════════
# WebView 扩展
# ═══════════════════════════════════════════════════════════════
class WebView(Stub):
"""WebView — Web视图扩展"""
RENDERER_PRIORITY_WAIVED = RENDERER_PRIORITY_WAIVED
RENDERER_PRIORITY_BOUND = RENDERER_PRIORITY_BOUND
RENDERER_PRIORITY_IMPORTANT = RENDERER_PRIORITY_IMPORTANT
SCHEME_HTTP = SCHEME_HTTP
SCHEME_HTTPS = SCHEME_HTTPS
SCHEME_FILE = SCHEME_FILE
SCHEME_ABOUT = SCHEME_ABOUT
SCHEME_DATA = SCHEME_DATA
SCHEME_JAVASCRIPT = SCHEME_JAVASCRIPT
LOAD_DEFAULT = LOAD_DEFAULT
LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
LOAD_NO_CACHE = LOAD_NO_CACHE
LOAD_NORMAL = LOAD_NORMAL
OVER_SCROLL_NEVER = OVER_SCROLL_NEVER
OVER_SCROLL_ALWAYS = OVER_SCROLL_ALWAYS
OVER_SCROLL_IF_CONTENT_SCROLLS = OVER_SCROLL_IF_CONTENT_SCROLLS
class WebViewTransport(Stub):
"""WebView.WebViewTransport — WebView传输"""
def __init__(self):
super().__init__()
self._webview: Optional[WebView] = None
def setWebView(self, webview: "WebView") -> None:
self._webview = webview
def getWebView(self) -> Optional["WebView"]:
return self._webview
def __init__(self, context: Any = None):
super().__init__()
self._url: Optional[str] = None
self._content: Optional[str] = None
self._settings: Optional["WebSettings"] = None
self._client: Optional["WebViewClient"] = None
self._chrome_client: Optional["WebChromeClient"] = None
self._web_message_listeners: Dict[str, WebMessageListener] = {}
self._renderer_priority: int = self.RENDERER_PRIORITY_BOUND
self._renderer_priority_overridden = False
self._lock = threading.Lock()
def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None) -> None:
self._url = url
self._content = None
if self._client:
self._client.onPageStarted(self, url, None)
def loadData(self, data: str, mime_type: str = "text/html",
encoding: str = "utf-8") -> None:
self._content = data
self._url = "data:text/html;charset=utf-8," + data[:100]
def loadDataWithBaseURL(self, base_url: str, data: str,
mime_type: str, encoding: str,
history_url: Optional[str]) -> None:
self._content = data
self._url = base_url
def postUrl(self, url: str, post_data: bytes) -> None:
self._url = url
def getUrl(self) -> Optional[str]:
return self._url
def getTitle(self) -> str:
return ""
def getSettings(self) -> "WebSettings":
if self._settings is None:
self._settings = WebSettings(self)
return self._settings
def setWebViewClient(self, client: "WebViewClient") -> None:
self._client = client
def getWebViewClient(self) -> Optional["WebViewClient"]:
return self._client
def setWebChromeClient(self, client: "WebChromeClient") -> None:
self._chrome_client = client
def getWebChromeClient(self) -> Optional["WebChromeClient"]:
return self._chrome_client
def setWebMessageListener(self, js_object_name: str,
listener: WebMessageListener) -> None:
with self._lock:
self._web_message_listeners[js_object_name] = listener
def addJavascriptInterface(self, obj: Any, name: str) -> None:
pass
def removeJavascriptInterface(self, name: str) -> None:
pass
def evaluateJavascript(self, script: str, callback: Optional[Callable] = None) -> None:
pass
def evaluateJavascriptForTests(self, script: str, callback: Optional[Callable] = None) -> None:
pass
def canGoBack(self) -> bool:
return False
def canGoForward(self) -> bool:
return False
def goBack(self) -> None:
pass
def goForward(self) -> None:
pass
def reload(self) -> None:
if self._url:
self.loadUrl(self._url)
def stopLoading(self) -> None:
pass
def clearHistory(self) -> None:
pass
def clearCache(self, include_disk: bool) -> None:
pass
def clearFormData(self) -> None:
pass
def destroy(self) -> None:
pass
def onPause(self) -> None:
pass
def onResume(self) -> None:
pass
def isPaused(self) -> bool:
return False
def pageUp(self, top: bool) -> bool:
return True
def pageDown(self, bottom: bool) -> bool:
return True
def setInitialScale(self, scale: int) -> None:
pass
def getScale(self) -> float:
return 1.0
def setRendererPriorityPolicy(self, priority: int, overridden: bool) -> None:
self._renderer_priority = priority
self._renderer_priority_overridden = overridden
def getRendererRequestedPriority(self) -> int:
return self._renderer_priority
def getRendererPriorityWaivedWhenNotVisible(self) -> bool:
return self._renderer_priority_overridden
def setNetworkAvailable(self, available: bool) -> None:
pass
def setLayoutParams(self, params: Any) -> None:
pass
def toString(self) -> str:
return f"WebView(url={self._url})"
# ═══════════════════════════════════════════════════════════════
# WebSettings 扩展
# ═══════════════════════════════════════════════════════════════
class WebSettings(Stub):
"""WebSettings — Web设置扩展"""
LOAD_DEFAULT = LOAD_DEFAULT
LOAD_CACHE_ONLY = LOAD_CACHE_ONLY
LOAD_CACHE_ELSE_NETWORK = LOAD_CACHE_ELSE_NETWORK
LOAD_NO_CACHE = LOAD_NO_CACHE
LOAD_NORMAL = LOAD_NORMAL
MIXED_CONTENT_ALWAYS_ALLOW = 0
MIXED_CONTENT_NEVER_ALLOW = 1
MIXED_CONTENT_COMPATIBILITY_MODE = 2
LAYOUT_ALGORITHM_NORMAL = 0
LAYOUT_ALGORITHM_SINGLE_COLUMN = 1
LAYOUT_ALGORITHM_NARROW_COLUMNS = 2
LAYOUT_ALGORITHM_TEXT_AUTOSIZING = 3
PLUGIN_STATE_ON = 0
PLUGIN_STATE_ON_DEMAND = 1
PLUGIN_STATE_OFF = 2
RENDER_GOOGLE_SUIT = 0
RENDER_PRIORITY_NORMAL = 0
RENDER_PRIORITY_HIGH = 1
RENDER_PRIORITY_LOW = 2
TEXT_AUTOSIZING_TEXT_SIZE_INCREMENT = 0
USER_AGENT_DESKTOP = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
USER_AGENT_MOBILE = "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
def __init__(self, webview: Optional[WebView] = None):
super().__init__()
self._webview = webview
self._java_script_enabled = False
self._java_script_can_open_windows = False
self._allow_file_access = True
self._allow_file_access_from_file_urls = True
self._allow_universal_access_from_file_urls = False
self._built_in_zoom_controls = True
self._display_zoom_controls = True
self._support_zoom = True
self._load_with_overview_mode = False
self._use_wide_viewport = True
self._dom_storage_enabled = True
self._database_enabled = True
self._app_cache_enabled = True
self._cache_mode = LOAD_DEFAULT
self._user_agent_string: Optional[str] = None
self._default_font_size: int = 16
self._default_fixed_font_size: int = 13
self._minimum_font_size: int = 8
self._minimum_logical_font_size: int = 8
self._text_zoom: int = 100
self._standard_font_family: str = "sans-serif"
self._serif_font_family: str = "serif"
self._sans_serif_font_family: str = "sans-serif"
self._fixed_font_family: str = "monospace"
self._cursive_font_family: str = "cursive"
self._fantasy_font_family: str = "fantasy"
self._default_text_encoding: str = "UTF-8"
self._layout_algorithm = self.LAYOUT_ALGORITHM_NORMAL
self._block_network_image = False
self._block_network_loads = False
self._accept_cookies = True
self._mixed_content_mode = self.MIXED_CONTENT_NEVER_ALLOW
self._offscreen_prefetch_rss = False
self._safe_browsing_enabled = True
self._save_form_data = True
self._save_password = False
self._need_initial_focus = True
self._support_multiple_windows = False
self._allow_content_access = True
self._loads_images_automatically = True
self._javascript_enabled = False
self._media_playback_requires_user_gesture = True
def setJavaScriptEnabled(self, enabled: bool) -> None:
self._javascript_enabled = enabled
def getJavaScriptEnabled(self) -> bool:
return self._javascript_enabled
def setJavaScriptCanOpenWindowsAutomatically(self, can: bool) -> None:
self._java_script_can_open_windows = can
def getJavaScriptCanOpenWindowsAutomatically(self) -> bool:
return self._java_script_can_open_windows
def setAllowFileAccess(self, allow: bool) -> None:
self._allow_file_access = allow
def getAllowFileAccess(self) -> bool:
return self._allow_file_access
def setAllowFileAccessFromFileURLs(self, allow: bool) -> None:
self._allow_file_access_from_file_urls = allow
def getAllowFileAccessFromFileURLs(self) -> bool:
return self._allow_file_access_from_file_urls
def setAllowUniversalAccessFromFileURLs(self, allow: bool) -> None:
self._allow_universal_access_from_file_urls = allow
def getAllowUniversalAccessFromFileURLs(self) -> bool:
return self._allow_universal_access_from_file_urls
def setBuiltInZoomControls(self, enabled: bool) -> None:
self._built_in_zoom_controls = enabled
def getBuiltInZoomControls(self) -> bool:
return self._built_in_zoom_controls
def setDisplayZoomControls(self, enabled: bool) -> None:
self._display_zoom_controls = enabled
def getDisplayZoomControls(self) -> bool:
return self._display_zoom_controls
def setSupportZoom(self, support: bool) -> None:
self._support_zoom = support
def supportZoom(self) -> bool:
return self._support_zoom
def setLoadWithOverviewMode(self, overview: bool) -> None:
self._load_with_overview_mode = overview
def getLoadWithOverviewMode(self) -> bool:
return self._load_with_overview_mode
def setUseWideViewPort(self, use: bool) -> None:
self._use_wide_viewport = use
def getUseWideViewPort(self) -> bool:
return self._use_wide_viewport
def setDomStorageEnabled(self, enabled: bool) -> None:
self._dom_storage_enabled = enabled
def getDomStorageEnabled(self) -> bool:
return self._dom_storage_enabled
def setDatabaseEnabled(self, enabled: bool) -> None:
self._database_enabled = enabled
def getDatabaseEnabled(self) -> bool:
return self._database_enabled
def setAppCacheEnabled(self, enabled: bool) -> None:
self._app_cache_enabled = enabled
def getAppCacheEnabled(self) -> bool:
return self._app_cache_enabled
def setCacheMode(self, mode: int) -> None:
self._cache_mode = mode
def getCacheMode(self) -> int:
return self._cache_mode
def setUserAgentString(self, ua: Optional[str]) -> None:
self._user_agent_string = ua
def getUserAgentString(self) -> str:
return self._user_agent_string or self.USER_AGENT_MOBILE
def setDefaultFontSize(self, size: int) -> None:
self._default_font_size = max(1, size)
def getDefaultFontSize(self) -> int:
return self._default_font_size
def setDefaultFixedFontSize(self, size: int) -> None:
self._default_fixed_font_size = max(1, size)
def getDefaultFixedFontSize(self) -> int:
return self._default_fixed_font_size
def setMinimumFontSize(self, size: int) -> None:
self._minimum_font_size = max(1, size)
def getMinimumFontSize(self) -> int:
return self._minimum_font_size
def setTextZoom(self, text_zoom: int) -> None:
self._text_zoom = max(50, min(200, text_zoom))
def getTextZoom(self) -> int:
return self._text_zoom
def setStandardFontFamily(self, font: str) -> None:
self._standard_font_family = font
def getStandardFontFamily(self) -> str:
return self._standard_font_family
def setSerifFontFamily(self, font: str) -> None:
self._serif_font_family = font
def getSerifFontFamily(self) -> str:
return self._serif_font_family
def setSansSerifFontFamily(self, font: str) -> None:
self._sans_serif_font_family = font
def getSansSerifFontFamily(self) -> str:
return self._sans_serif_font_family
def setFixedFontFamily(self, font: str) -> None:
self._fixed_font_family = font
def getFixedFontFamily(self) -> str:
return self._fixed_font_family
def setCursiveFontFamily(self, font: str) -> None:
self._cursive_font_family = font
def getCursiveFontFamily(self) -> str:
return self._cursive_font_family
def setFantasyFontFamily(self, font: str) -> None:
self._fantasy_font_family = font
def getFantasyFontFamily(self) -> str:
return self._fantasy_font_family
def setDefaultTextEncodingName(self, encoding: str) -> None:
self._default_text_encoding = encoding
def getDefaultTextEncodingName(self) -> str:
return self._default_text_encoding
def setLayoutAlgorithm(self, algorithm: int) -> None:
self._layout_algorithm = algorithm
def getLayoutAlgorithm(self) -> int:
return self._layout_algorithm
def setBlockNetworkImage(self, block: bool) -> None:
self._block_network_image = block
def getBlockNetworkImage(self) -> bool:
return self._block_network_image
def setBlockNetworkLoads(self, block: bool) -> None:
self._block_network_loads = block
def getBlockNetworkLoads(self) -> bool:
return self._block_network_loads
def setMixedContentMode(self, mode: int) -> None:
self._mixed_content_mode = mode
def getMixedContentMode(self) -> int:
return self._mixed_content_mode
def setLoadsImagesAutomatically(self, enabled: bool) -> None:
self._loads_images_automatically = enabled
def getLoadsImagesAutomatically(self) -> bool:
return self._loads_images_automatically
def setMediaPlaybackRequiresUserGesture(self, requires: bool) -> None:
self._media_playback_requires_user_gesture = requires
def getMediaPlaybackRequiresUserGesture(self) -> bool:
return self._media_playback_requires_user_gesture
def setSupportMultipleWindows(self, support: bool) -> None:
self._support_multiple_windows = support
def supportMultipleWindows(self) -> bool:
return self._support_multiple_windows
def setSaveFormData(self, save: bool) -> None:
self._save_form_data = save
def getSaveFormData(self) -> bool:
return self._save_form_data
def setSavePassword(self, save: bool) -> None:
self._save_password = save
def getSavePassword(self) -> bool:
return self._save_password
def setNeedInitialFocus(self, need: bool) -> None:
self._need_initial_focus = need
def getNeedInitialFocus(self) -> bool:
return self._need_initial_focus
def setSafeBrowsingEnabled(self, enabled: bool) -> None:
self._safe_browsing_enabled = enabled
def getSafeBrowsingEnabled(self) -> bool:
return self._safe_browsing_enabled
def toString(self) -> str:
return (f"WebSettings(js={self._javascript_enabled}, "
f"zoom={self._support_zoom})")
# ═══════════════════════════════════════════════════════════════
# WebViewClient 扩展
# ═══════════════════════════════════════════════════════════════
class WebViewClient(Stub):
"""WebViewClient — Web视图客户端扩展"""
def __init__(self):
super().__init__()
def shouldOverrideUrlLoading(self, view: WebView, request: WebResourceRequest) -> bool:
return False
def shouldOverrideKeyEvent(self, view: WebView, event: Any) -> bool:
return False
def onPageStarted(self, view: WebView, url: str, favicon: Any) -> None:
pass
def onPageFinished(self, view: WebView, url: str) -> None:
pass
def onLoadResource(self, view: WebView, url: str) -> None:
pass
def onPageCommitVisible(self, view: WebView, url: str) -> None:
pass
def shouldInterceptRequest(self, view: WebView, request: WebResourceRequest) -> Optional[WebResourceResponse]:
return None
def onReceivedError(self, view: WebView, request: WebResourceRequest,
error: WebResourceError) -> None:
pass
def onReceivedHttpError(self, view: WebView, request: WebResourceRequest,
error_response: WebResourceResponse) -> None:
pass
def onReceivedHttpAuthRequest(self, view: WebView, handler: Any,
host: str, realm: str) -> None:
pass
def onReceivedLoginRequest(self, view: WebView, realm: str,
account: str, args: str) -> None:
pass
def onReceivedSslError(self, view: WebView, handler: Any,
error: Any) -> None:
pass
def onReceivedClientCertRequest(self, view: WebView,
request: Any) -> None:
pass
def onFormResubmission(self, view: WebView, dont_resend: Any,
resend: Any) -> None:
pass
def doUpdateVisitedHistory(self, view: WebView, url: str,
is_reloa: bool) -> None:
pass
def onUnhandledKeyEvent(self, view: WebView, event: Any) -> None:
pass
def onScaleChanged(self, view: WebView, old_scale: float, new_scale: float) -> None:
pass
def onRenderProcessGone(self, view: WebView, detail: Any) -> bool:
return True
def onUnhandledInputEvent(self, view: WebView, event: Any) -> None:
pass
def safebrowsingOnBackForwardTransitioned(self, view: WebView,
safe: bool) -> None:
pass
def toString(self) -> str:
return "WebViewClient()"
# ═══════════════════════════════════════════════════════════════
# WebChromeClient 扩展
# ═══════════════════════════════════════════════════════════════
class WebChromeClient(Stub):
"""WebChromeClient — Web Chrome客户端扩展"""
GET_DEFAULT_VIDEO_POSTER = WEB_CHROME_CLIENT_GET_DEFAULT_VIDEO_POSTER
GET_VISITED_HISTORY = WEB_CHROME_CLIENT_GET_VISITED_HISTORY
def __init__(self):
super().__init__()
def onProgressChanged(self, view: WebView, new_progress: int) -> None:
pass
def onReceivedTitle(self, view: WebView, title: str) -> None:
pass
def onReceivedIcon(self, view: WebView, icon: Any) -> None:
pass
def onReceivedTouchIconUrl(self, view: WebView, url: str,
precomposed: bool) -> None:
pass
def onShowCustomView(self, view: Any, callback: Any) -> None:
pass
def onHideCustomView(self) -> None:
pass
def onCreateWindow(self, view: WebView, is_dialog: bool,
is_user_gesture: bool,
result_msg: Any) -> bool:
return False
def onRequestFocus(self, view: WebView) -> None:
pass
def onCloseWindow(self, window: WebView) -> None:
pass
def onJsAlert(self, view: WebView, url: str, message: str,
result: Any) -> bool:
return False
def onJsConfirm(self, view: WebView, url: str, message: str,
result: Any) -> bool:
return False
def onJsPrompt(self, view: WebView, url: str, message: str,
default_value: str, result: Any) -> bool:
return False
def onJsBeforeUnload(self, view: WebView, url: str, message: str,
result: Any) -> bool:
return False
def onConsoleMessage(self, console_message: Any) -> bool:
return True
def getVideoLoadingProgressView(self) -> Optional[Any]:
return None
def getDefaultVideoPoster(self) -> Optional[Any]:
return None
def onShowFileChooser(self, view: WebView, callback: Any,
params: Any) -> bool:
return False
def onPermissionRequest(self, request: Any) -> None:
pass
def onPermissionRequestCanceled(self, request: Any) -> None:
pass
def onGeolocationPermissionsShowPrompt(self, origin: str,
callback: Any) -> None:
pass
def onGeolocationPermissionsHidePrompt(self) -> None:
pass
def onJsTimeout(self) -> bool:
return True
def onExceededDatabaseQuota(self, url: str, database_id: str,
quota: int, estimated: int,
quota_updater: Any) -> None:
pass
def onReachedMaxAppCacheSize(self, space_needed: int, total: int,
quota_updater: Any) -> None:
pass
def onConsoleMessage(self, source_id: str, message: str,
line_number: int, msg_type: int) -> bool:
return True
def toString(self) -> str:
return "WebChromeClient()"
# ═══════════════════════════════════════════════════════════════
# CookieManager 扩展
# ═══════════════════════════════════════════════════════════════
class CookieManager(Stub):
"""CookieManager — Cookie管理器扩展"""
_instance: Optional["CookieManager"] = None
_lock = threading.Lock()
def __init__(self):
super().__init__()
self._cookies: Dict[str, Dict[str, str]] = {}
self._accept_cookie = True
@staticmethod
def getInstance() -> "CookieManager":
with CookieManager._lock:
if CookieManager._instance is None:
CookieManager._instance = CookieManager()
return CookieManager._instance
def setAcceptCookie(self, accept: bool) -> None:
self._accept_cookie = accept
def acceptCookie(self) -> bool:
return self._accept_cookie
def setAcceptThirdPartyCookies(self, webview: WebView, accept: bool) -> None:
pass
def acceptThirdPartyCookies(self, webview: WebView) -> bool:
return False
def setCookie(self, url: str, value: str) -> None:
domain = self._extract_domain(url)
if domain not in self._cookies:
self._cookies[domain] = {}
if "=" in value:
key, val = value.split("=", 1)
self._cookies[domain][key.strip()] = val.strip()
def getCookie(self, url: str) -> Optional[str]:
domain = self._extract_domain(url)
if domain in self._cookies:
parts = [f"{k}={v}" for k, v in self._cookies[domain].items()]
return "; ".join(parts)
return None
def removeSessionCookies(self) -> None:
self._cookies.clear()
def removeAllCookies(self) -> None:
self._cookies.clear()
def removeExpiredCookie(self) -> None:
pass
def hasCookies(self) -> bool:
return bool(self._cookies)
def _extract_domain(self, url: str) -> str:
if "://" in url:
url = url.split("://", 1)[1]
return url.split("/")[0].split(":")[0]
def flush(self) -> None:
pass
def toString(self) -> str:
return f"CookieManager(domains={len(self._cookies)})"
# ═══════════════════════════════════════════════════════════════
# GeolocationPermissions / JsResult / JsPromptResult
# ═══════════════════════════════════════════════════════════════
class GeolocationPermissions(Stub):
"""GeolocationPermissions — 地理位置权限"""
_origins: Dict[str, bool] = {}
_lock = threading.Lock()
@classmethod
def getInstance(cls) -> "GeolocationPermissions":
return cls()
def getOrigins(self, callback: Callable) -> None:
with self._lock:
callback(list(self._origins.keys()))
def getAllowed(self, origin: str, callback: Callable) -> None:
with self._lock:
callback(origin, self._origins.get(origin, False), False)
def clear(self, origin: str) -> None:
with self._lock:
self._origins.pop(origin, None)
def clearAll(self) -> None:
with self._lock:
self._origins.clear()
def allow(self, origin: str, allow: bool) -> None:
with self._lock:
self._origins[origin] = allow
class JsResult(Stub):
"""JsResult — JavaScript 对话框结果"""
def __init__(self):
super().__init__()
self._result: Optional[bool] = None
def confirm(self) -> None:
self._result = True
def cancel(self) -> None:
self._result = False
def getResult(self) -> Optional[bool]:
return self._result
def toString(self) -> str:
return f"JsResult(result={self._result})"
class JsPromptResult(JsResult):
"""JsPromptResult — JavaScript 提示框结果"""
def __init__(self):
super().__init__()
self._string_result: str = ""
def confirm(self, result: str) -> None:
super().confirm()
self._string_result = result
def getStringResult(self) -> str:
return self._string_result
def toString(self) -> str:
return f"JsPromptResult(result={self._result}, string={self._string_result})"
class HttpAuthHandler(Stub):
"""HttpAuthHandler — HTTP 认证处理器"""
def __init__(self):
super().__init__()
self._handled = False
def proceed(self, username: str, password: str) -> None:
self._handled = True
def cancel(self) -> None:
self._handled = True
def useHttpAuthUsernamePassword(self, use: bool) -> None:
pass
def isHandled(self) -> bool:
return self._handled
def toString(self) -> str:
return f"HttpAuthHandler(handled={self._handled})"
class SslErrorHandler(Stub):
"""SslErrorHandler — SSL 错误处理器"""
def __init__(self):
super().__init__()
self._handled = False
def proceed(self) -> None:
self._handled = True
def cancel(self) -> None:
self._handled = True
def isHandled(self) -> bool:
return self._handled
def toString(self) -> str:
return f"SslErrorHandler(handled={self._handled})"
class ClientCertRequest(Stub):
"""ClientCertRequest — 客户端证书请求"""
def __init__(self):
super().__init__()
self._handled = False
def getHost(self) -> str:
return ""
def getPort(self) -> int:
return 443
def getKeyTypes(self) -> List[str]:
return ["RSA"]
def getPrincipals(self) -> List[str]:
return []
def cancel(self) -> None:
self._handled = True
def proceed(self, private_key: Any, chain: List[Any]) -> None:
self._handled = True
def ignore(self) -> None:
self._handled = True
def isHandled(self) -> bool:
return self._handled
class PermissionRequest(Stub):
"""PermissionRequest — 权限请求"""
RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE"
RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE"
RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID"
RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX"
def __init__(self):
super().__init__()
self._origin: Optional[str] = None
self._resources: List[str] = []
self._granted = False
def getOrigin(self) -> str:
return self._origin or ""
def getResources(self) -> List[str]:
return list(self._resources)
def grant(self, resources: List[str]) -> None:
self._granted = True
def deny(self) -> None:
self._granted = False
def isGranted(self) -> bool:
return self._granted
def toString(self) -> str:
return f"PermissionRequest(origin={self._origin}, granted={self._granted})"
class ConsoleMessage(Stub):
"""ConsoleMessage — 控制台消息"""
MessageLevel = type("MessageLevel", (), {
"TIP": 0, "LOG": 1, "WARNING": 2, "ERROR": 3, "DEBUG": 4
})
def __init__(self, message: str = "", source_id: str = "",
line_number: int = 0, msg_level: int = MessageLevel.LOG):
super().__init__()
self._message = message
self._source_id = source_id
self._line_number = line_number
self._msg_level = msg_level
def message(self) -> str:
return self._message
def sourceId(self) -> str:
return self._source_id
def lineNumber(self) -> int:
return self._line_number
def messageLevel(self) -> int:
return self._msg_level
def toString(self) -> str:
return f"ConsoleMessage({self._message[:50]})"
class ValueCallback(Stub):
"""ValueCallback — 值回调接口"""
def onReceiveValue(self, value: Any) -> None:
pass
# ═══════════════════════════════════════════════════════════════
# WebBackForwardList / WebHistoryItem / WebIconDatabase / etc.
# ═══════════════════════════════════════════════════════════════
class WebBackForwardList(Stub):
"""WebBackForwardList — 后退/前进列表"""
def __init__(self):
super().__init__()
self._items: List["WebHistoryItem"] = []
self._current_index: int = -1
def getCurrentItem(self) -> Optional["WebHistoryItem"]:
if 0 <= self._current_index < len(self._items):
return self._items[self._current_index]
return None
def getCurrentIndex(self) -> int:
return self._current_index
def getItemAtIndex(self, index: int) -> Optional["WebHistoryItem"]:
if 0 <= index < len(self._items):
return self._items[index]
return None
def getSize(self) -> int:
return len(self._items)
def toString(self) -> str:
return f"WebBackForwardList(size={len(self._items)}, current={self._current_index})"
class WebHistoryItem(Stub):
"""WebHistoryItem — Web历史条目"""
def __init__(self, url: str = "", title: str = "",
favicon: Any = None):
super().__init__()
self._url = url
self._title = title
self._favicon = favicon
def getUrl(self) -> str:
return self._url
def getTitle(self) -> str:
return self._title
def getFavicon(self) -> Optional[Any]:
return self._favicon
def setUrl(self, url: str) -> None:
self._url = url
def setTitle(self, title: str) -> None:
self._title = title
def setFavicon(self, favicon: Any) -> None:
self._favicon = favicon
def toString(self) -> str:
return f"WebHistoryItem(url={self._url}, title={self._title})"
class WebIconDatabase(Stub):
"""WebIconDatabase — Web图标数据库"""
_instance: Optional["WebIconDatabase"] = None
@staticmethod
def getInstance() -> "WebIconDatabase":
if WebIconDatabase._instance is None:
WebIconDatabase._instance = WebIconDatabase()
return WebIconDatabase._instance
def open(self, path: str) -> None:
pass
def close(self) -> None:
pass
def removeAllIcons(self) -> None:
pass
def requestIconForPageUrl(self, url: str, callback: Callable) -> None:
callback(url, None)
def retainIconForPageUrl(self, url: str) -> None:
pass
def releaseIconForPageUrl(self, url: str) -> None:
pass
def getIconForPageUrl(self, url: str) -> Optional[Any]:
return None
def toString(self) -> str:
return "WebIconDatabase()"
class WebViewDatabase(Stub):
"""WebViewDatabase — WebView数据库"""
_instance: Optional["WebViewDatabase"] = None
@staticmethod
def getInstance(context: Any) -> "WebViewDatabase":
if WebViewDatabase._instance is None:
WebViewDatabase._instance = WebViewDatabase()
return WebViewDatabase._instance
def hasFormData(self) -> bool:
return False
def clearFormData(self) -> None:
pass
def hasUsernamePassword(self) -> bool:
return False
def clearUsernamePassword(self) -> None:
pass
def hasHttpAuthUsernamePassword(self) -> bool:
return False
def clearHttpAuthUsernamePassword(self) -> None:
pass
def toString(self) -> str:
return "WebViewDatabase()"
class WebViewFragment(Stub):
"""WebViewFragment — WebView片段"""
def __init__(self):
super().__init__()
self._webview: Optional[WebView] = None
def onCreateView(self, inflater: Any, container: Any,
savedInstanceState: Any) -> Optional[WebView]:
self._webview = WebView()
return self._webview
def onPause(self) -> None:
if self._webview:
self._webview.onPause()
def onResume(self) -> None:
if self._webview:
self._webview.onResume()
def onDestroyView(self) -> None:
if self._webview:
self._webview.destroy()
def getWebView(self) -> Optional[WebView]:
return self._webview
def toString(self) -> str:
return f"WebViewFragment(webview={'yes' if self._webview else 'no'})"
class DateSorter(Stub):
"""DateSorter — 日期排序器"""
DAY_COUNT = 5
def __init__(self, context: Any):
super().__init__()
self._bounds: List[int] = [0, 0, 0, 0, 0]
self._labels: List[str] = ["Today", "Yesterday", "Earlier"]
def getBounds(self) -> List[int]:
return list(self._bounds)
def getLabel(self, index: int) -> str:
if 0 <= index < len(self._labels):
return self._labels[index]
return ""
def toString(self) -> str:
return "DateSorter()"
class FindActionModeCallback(Stub):
"""FindActionModeCallback — 查找操作模式回调"""
def __init__(self, context: Any = None):
super().__init__()
self._search_text: str = ""
self._global_search_count: int = 0
self._match_count: int = 0
def finishActionMode(self) -> None:
pass
def setText(self, text: str) -> None:
self._search_text = text
def getText(self) -> str:
return self._search_text
def setGlobalSearchCount(self, count: int) -> None:
self._global_search_count = count
def getGlobalSearchCount(self) -> int:
return self._global_search_count
def setMatchCount(self, count: int) -> None:
self._match_count = count
def getMatchCount(self) -> int:
return self._match_count
def toString(self) -> str:
return (f"FindActionModeCallback(search={self._search_text}, "
f"matches={self._match_count})")
class JsDialogHelper(Stub):
"""JsDialogHelper — JavaScript 对话框助手"""
ALERT = 1
CONFIRM = 2
PROMPT = 3
UNLOAD = 4
def __init__(self, result: JsResult, default_value: str = "",
dialog_type: int = ALERT, message: str = ""):
super().__init__()
self._result = result
self._default_value = default_value
self._dialog_type = dialog_type
self._message = message
def getDialogType(self) -> int:
return self._dialog_type
def getMessage(self) -> str:
return self._message
def getDefaultValue(self) -> str:
return self._default_value
def invokeCallback(self, result: Any) -> None:
if self._result:
self._result.confirm()
def cancelDialog(self) -> None:
if self._result:
self._result.cancel()
def toString(self) -> str:
types = {1: "ALERT", 2: "CONFIRM", 3: "PROMPT", 4: "UNLOAD"}
return f"JsDialogHelper(type={types.get(self._dialog_type, 'UNKNOWN')})"