992 lines
31 KiB
Python
992 lines
31 KiB
Python
"""
|
|
Android WebKit 组件 — WebView, WebSettings, WebViewClient, WebChromeClient 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
|
|
from .._core import (
|
|
Stub, AndroidOnlyError, android_context,
|
|
resolve_android_path, to_android_path,
|
|
_sdcard_root, _app_data_dir, _package_name,
|
|
)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 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):
|
|
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 {}
|
|
|
|
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 toString(self) -> str:
|
|
return f"WebResourceRequest(url={self._url})"
|
|
|
|
|
|
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)
|
|
|
|
|
|
class WebResourceError(Stub):
|
|
"""WebResourceError — 资源错误"""
|
|
|
|
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
|
|
|
|
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
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebMessage / WebMessagePort
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebMessage(Stub):
|
|
"""WebMessage — Web 消息"""
|
|
|
|
def __init__(self, data: str = ""):
|
|
super().__init__()
|
|
self._data = data
|
|
|
|
def getData(self) -> str:
|
|
return self._data
|
|
|
|
|
|
class WebMessagePort(Stub):
|
|
"""WebMessagePort — Web 消息端口"""
|
|
|
|
def postMessage(self, message: WebMessage):
|
|
pass
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
def setWebMessageCallback(self, callback: Any):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# JavascriptInterface
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class JavascriptInterface(Stub):
|
|
"""JavascriptInterface — JavaScript 接口注解"""
|
|
|
|
def __init__(self, value: str = ""):
|
|
super().__init__()
|
|
self._value = value
|
|
|
|
def getValue(self) -> str:
|
|
return self._value
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# JsResult / JsPromptResult
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class JsResult(Stub):
|
|
"""JsResult — JS 对话框结果"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._confirmed = False
|
|
|
|
def confirm(self):
|
|
self._confirmed = True
|
|
|
|
def cancel(self):
|
|
self._confirmed = False
|
|
|
|
|
|
class JsPromptResult(JsResult):
|
|
"""JsPromptResult — JS 提示结果"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._string_result: str = ""
|
|
|
|
def confirm(self, result: str = ""):
|
|
self._confirmed = True
|
|
self._string_result = result
|
|
|
|
def getStringResult(self) -> str:
|
|
return self._string_result
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# HttpAuthHandler / SslErrorHandler
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class HttpAuthHandler(Stub):
|
|
"""HttpAuthHandler — HTTP 认证处理器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._proceeded = False
|
|
self._cancelled = False
|
|
|
|
def proceed(self, username: str, password: str):
|
|
self._proceeded = True
|
|
|
|
def cancel(self):
|
|
self._cancelled = True
|
|
|
|
def useHttpAuthUsernamePassword(self) -> bool:
|
|
return False
|
|
|
|
|
|
class SslErrorHandler(Stub):
|
|
"""SslErrorHandler — SSL 错误处理器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._proceeded = False
|
|
self._cancelled = False
|
|
|
|
def proceed(self):
|
|
self._proceeded = True
|
|
|
|
def cancel(self):
|
|
self._cancelled = True
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PermissionRequest
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
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: Any = None
|
|
self._resources: List[str] = []
|
|
self._granted_resources: List[str] = []
|
|
|
|
def getOrigin(self) -> Any:
|
|
return self._origin
|
|
|
|
def getResources(self) -> List[str]:
|
|
return list(self._resources)
|
|
|
|
def getGrantedResources(self) -> List[str]:
|
|
return list(self._granted_resources)
|
|
|
|
def grant(self, resources: List[str]):
|
|
self._granted_resources = list(resources)
|
|
|
|
def deny(self):
|
|
self._granted_resources.clear()
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# GeolocationPermissions / WebStorage
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class GeolocationPermissions(Stub):
|
|
"""GeolocationPermissions — 地理位置权限"""
|
|
|
|
@staticmethod
|
|
def getInstance() -> "GeolocationPermissions":
|
|
return GeolocationPermissions()
|
|
|
|
def allow(self, origin: str):
|
|
pass
|
|
|
|
def clear(self, origin: str):
|
|
pass
|
|
|
|
def clearAll(self):
|
|
pass
|
|
|
|
def getAllowed(self, origin: str, callback: Any):
|
|
pass
|
|
|
|
def getOrigins(self, callback: Any):
|
|
pass
|
|
|
|
|
|
class WebStorage(Stub):
|
|
"""WebStorage — Web 存储"""
|
|
|
|
@staticmethod
|
|
def getInstance() -> "WebStorage":
|
|
return WebStorage()
|
|
|
|
def deleteAllData(self):
|
|
pass
|
|
|
|
def deleteOrigin(self, origin: str):
|
|
pass
|
|
|
|
def getOrigins(self, callback: Any):
|
|
pass
|
|
|
|
def getQuotaForOrigin(self, origin: str, callback: Any):
|
|
pass
|
|
|
|
def getUsageForOrigin(self, origin: str, callback: Any):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebBackForwardList / WebHistoryItem
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebHistoryItem(Stub):
|
|
"""WebHistoryItem — 历史项"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._url: str = ""
|
|
self._original_url: str = ""
|
|
self._title: str = ""
|
|
self._favicon: Any = None
|
|
|
|
def getUrl(self) -> str:
|
|
return self._url
|
|
|
|
def getOriginalUrl(self) -> str:
|
|
return self._original_url
|
|
|
|
def getTitle(self) -> str:
|
|
return self._title
|
|
|
|
def getFavicon(self) -> Any:
|
|
return self._favicon
|
|
|
|
def toString(self) -> str:
|
|
return f"WebHistoryItem(url={self._url})"
|
|
|
|
|
|
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)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CookieManager / CookieSyncManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CookieManager(Stub):
|
|
"""CookieManager — Cookie 管理器"""
|
|
|
|
_instance: Optional["CookieManager"] = None
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._accept_cookies: bool = True
|
|
self._accept_third_party: bool = True
|
|
self._cookies: Dict[str, str] = {}
|
|
|
|
@staticmethod
|
|
def getInstance() -> "CookieManager":
|
|
if CookieManager._instance is None:
|
|
CookieManager._instance = CookieManager()
|
|
return CookieManager._instance
|
|
|
|
def setAcceptCookies(self, accept: bool):
|
|
self._accept_cookies = accept
|
|
|
|
def acceptCookies(self) -> bool:
|
|
return self._accept_cookies
|
|
|
|
def setCookie(self, url: str, value: str):
|
|
if self._accept_cookies:
|
|
self._cookies[url] = value
|
|
|
|
def getCookie(self, url: str) -> Optional[str]:
|
|
return self._cookies.get(url)
|
|
|
|
def setAcceptThirdPartyCookies(self, webview: Any, accept: bool):
|
|
self._accept_third_party = accept
|
|
|
|
def acceptThirdPartyCookies(self) -> bool:
|
|
return self._accept_third_party
|
|
|
|
def removeSessionCookie(self):
|
|
pass
|
|
|
|
def removeAllCookies(self):
|
|
self._cookies.clear()
|
|
|
|
def removeAllCookiesSync(self):
|
|
self._cookies.clear()
|
|
|
|
def removeSessionCookies(self):
|
|
pass
|
|
|
|
def flush(self):
|
|
pass
|
|
|
|
def hasCookies(self) -> bool:
|
|
return bool(self._cookies)
|
|
|
|
def removeExpiredCookie(self):
|
|
pass
|
|
|
|
|
|
class CookieSyncManager(Stub):
|
|
"""CookieSyncManager — Cookie 同步管理器"""
|
|
|
|
_instance: Optional["CookieSyncManager"] = None
|
|
|
|
@staticmethod
|
|
def createInstance(context: Any) -> "CookieSyncManager":
|
|
if CookieSyncManager._instance is None:
|
|
CookieSyncManager._instance = CookieSyncManager()
|
|
return CookieSyncManager._instance
|
|
|
|
@staticmethod
|
|
def getInstance() -> "CookieSyncManager":
|
|
if CookieSyncManager._instance is None:
|
|
CookieSyncManager._instance = CookieSyncManager()
|
|
return CookieSyncManager._instance
|
|
|
|
def sync(self):
|
|
pass
|
|
|
|
def startSync(self):
|
|
pass
|
|
|
|
def stopSync(self):
|
|
pass
|
|
|
|
def resetSync(self):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebSettings
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebSettings(Stub):
|
|
"""WebSettings — WebView 设置"""
|
|
|
|
LOAD_DEFAULT = -1
|
|
LOAD_CACHE_ELSE_NETWORK = 1
|
|
LOAD_NO_CACHE = 2
|
|
LOAD_CACHE_ONLY = 3
|
|
|
|
MIXED_CONTENT_ALWAYS_ALLOW = 0
|
|
MIXED_CONTENT_NEVER_ALLOW = 1
|
|
MIXED_CONTENT_COMPATIBILITY_MODE = 2
|
|
|
|
class LayoutAlgorithm(Stub):
|
|
NORMAL = 0
|
|
SINGLE_COLUMN = 1
|
|
NARROW_COLUMNS = 2
|
|
TEXT_AUTOSIZING = 3
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._js_enabled: bool = True
|
|
self._dom_storage_enabled: bool = True
|
|
self._allow_file_access: bool = True
|
|
self._allow_content_access: bool = True
|
|
self._allow_file_access_from_urls: bool = False
|
|
self._allow_universal_access_from_urls: bool = False
|
|
self._built_in_zoom_controls: bool = True
|
|
self._display_zoom_controls: bool = True
|
|
self._support_zoom: bool = True
|
|
self._load_with_overview_mode: bool = False
|
|
self._use_wide_viewport: bool = False
|
|
self._user_agent_string: str = "Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36"
|
|
self._default_text_encoding: str = "UTF-8"
|
|
self._cache_mode: int = self.LOAD_DEFAULT
|
|
self._app_cache_enabled: bool = False
|
|
self._app_cache_path: str = ""
|
|
self._database_enabled: bool = False
|
|
self._geolocation_enabled: bool = False
|
|
self._js_can_open_windows: bool = False
|
|
self._loads_images_automatically: bool = True
|
|
self._block_network_image: bool = False
|
|
self._block_network_loads: bool = False
|
|
self._minimum_font_size: int = 8
|
|
self._default_font_size: int = 16
|
|
self._text_zoom: int = 100
|
|
self._layout_algorithm: int = WebSettings.LayoutAlgorithm.NORMAL
|
|
self._mixed_content_mode: int = self.MIXED_CONTENT_NEVER_ALLOW
|
|
self._offscreen_pre_raster: bool = False
|
|
self._safe_browsing_enabled: bool = True
|
|
self._javascript_can_open_windows_automatically: bool = False
|
|
|
|
def setJavaScriptEnabled(self, enabled: bool):
|
|
self._js_enabled = enabled
|
|
|
|
def setDomStorageEnabled(self, enabled: bool):
|
|
self._dom_storage_enabled = enabled
|
|
|
|
def setAllowFileAccess(self, allow: bool):
|
|
self._allow_file_access = allow
|
|
|
|
def setAllowContentAccess(self, allow: bool):
|
|
self._allow_content_access = allow
|
|
|
|
def setAllowFileAccessFromFileURLs(self, allow: bool):
|
|
self._allow_file_access_from_urls = allow
|
|
|
|
def setAllowUniversalAccessFromFileURLs(self, allow: bool):
|
|
self._allow_universal_access_from_urls = allow
|
|
|
|
def setBuiltInZoomControls(self, enabled: bool):
|
|
self._built_in_zoom_controls = enabled
|
|
|
|
def setDisplayZoomControls(self, enabled: bool):
|
|
self._display_zoom_controls = enabled
|
|
|
|
def setSupportZoom(self, support: bool):
|
|
self._support_zoom = support
|
|
|
|
def setLoadWithOverviewMode(self, overview: bool):
|
|
self._load_with_overview_mode = overview
|
|
|
|
def setUseWideViewPort(self, use: bool):
|
|
self._use_wide_viewport = use
|
|
|
|
def setUserAgentString(self, ua: str):
|
|
self._user_agent_string = ua
|
|
|
|
def getUserAgentString(self) -> str:
|
|
return self._user_agent_string
|
|
|
|
def setDefaultTextEncodingName(self, encoding: str):
|
|
self._default_text_encoding = encoding
|
|
|
|
def getDefaultTextEncodingName(self) -> str:
|
|
return self._default_text_encoding
|
|
|
|
def setCacheMode(self, mode: int):
|
|
self._cache_mode = mode
|
|
|
|
def getCacheMode(self) -> int:
|
|
return self._cache_mode
|
|
|
|
def setAppCacheEnabled(self, enabled: bool):
|
|
self._app_cache_enabled = enabled
|
|
|
|
def setAppCachePath(self, path: str):
|
|
self._app_cache_path = path
|
|
|
|
def setDatabaseEnabled(self, enabled: bool):
|
|
self._database_enabled = enabled
|
|
|
|
def setGeolocationEnabled(self, enabled: bool):
|
|
self._geolocation_enabled = enabled
|
|
|
|
def setJavaScriptCanOpenWindowsAutomatically(self, auto: bool):
|
|
self._javascript_can_open_windows_automatically = auto
|
|
|
|
def setLoadsImagesAutomatically(self, auto: bool):
|
|
self._loads_images_automatically = auto
|
|
|
|
def setBlockNetworkImage(self, block: bool):
|
|
self._block_network_image = block
|
|
|
|
def setBlockNetworkLoads(self, block: bool):
|
|
self._block_network_loads = block
|
|
|
|
def setMinimumFontSize(self, size: int):
|
|
self._minimum_font_size = size
|
|
|
|
def getMinimumFontSize(self) -> int:
|
|
return self._minimum_font_size
|
|
|
|
def setDefaultFontSize(self, size: int):
|
|
self._default_font_size = size
|
|
|
|
def getDefaultFontSize(self) -> int:
|
|
return self._default_font_size
|
|
|
|
def setTextZoom(self, zoom: int):
|
|
self._text_zoom = zoom
|
|
|
|
def getTextZoom(self) -> int:
|
|
return self._text_zoom
|
|
|
|
def setLayoutAlgorithm(self, algo: int):
|
|
self._layout_algorithm = algo
|
|
|
|
def getLayoutAlgorithm(self) -> int:
|
|
return self._layout_algorithm
|
|
|
|
def setMixedContentMode(self, mode: int):
|
|
self._mixed_content_mode = mode
|
|
|
|
def getMixedContentMode(self) -> int:
|
|
return self._mixed_content_mode
|
|
|
|
def setOffscreenPreRaster(self, enabled: bool):
|
|
self._offscreen_pre_raster = enabled
|
|
|
|
def getOffscreenPreRaster(self) -> bool:
|
|
return self._offscreen_pre_raster
|
|
|
|
def setSafeBrowsingEnabled(self, enabled: bool):
|
|
self._safe_browsing_enabled = enabled
|
|
|
|
def getSafeBrowsingEnabled(self) -> bool:
|
|
return self._safe_browsing_enabled
|
|
|
|
def toString(self) -> str:
|
|
return f"WebSettings(js={self._js_enabled})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebViewClient
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebViewClient(Stub):
|
|
"""WebViewClient — WebView 客户端"""
|
|
|
|
def onPageStarted(self, view: "WebView", url: str, favicon: Any):
|
|
pass
|
|
|
|
def onPageFinished(self, view: "WebView", url: str):
|
|
pass
|
|
|
|
def onLoadResource(self, view: "WebView", url: str):
|
|
pass
|
|
|
|
def shouldOverrideUrlLoading(self, view: "WebView", request: Any) -> bool:
|
|
return False
|
|
|
|
def shouldOverrideUrlLoading(self, view: "WebView", url: str) -> bool:
|
|
return False
|
|
|
|
def shouldInterceptRequest(self, view: "WebView", request: WebResourceRequest) -> Optional[WebResourceResponse]:
|
|
return None
|
|
|
|
def shouldInterceptRequest(self, view: "WebView", url: str) -> Optional[WebResourceResponse]:
|
|
return None
|
|
|
|
def onReceivedHttpError(self, view: "WebView", request: WebResourceRequest,
|
|
error_response: WebResourceResponse):
|
|
pass
|
|
|
|
def onReceivedSslError(self, view: "WebView", handler: SslErrorHandler, error: Any):
|
|
pass
|
|
|
|
def onReceivedClientCertRequest(self, view: "WebView", request: Any):
|
|
pass
|
|
|
|
def onReceivedHttpAuthRequest(self, view: "WebView", handler: HttpAuthHandler,
|
|
host: str, realm: str):
|
|
pass
|
|
|
|
def onFormResubmission(self, view: "WebView", dont_resend: Any, resend: Any):
|
|
pass
|
|
|
|
def doUpdateVisitedHistory(self, view: "WebView", url: str, is_reload: bool):
|
|
pass
|
|
|
|
def onScaleChanged(self, view: "WebView", old_scale: float, new_scale: float):
|
|
pass
|
|
|
|
def onUnhandledKeyEvent(self, view: "WebView", event: Any):
|
|
pass
|
|
|
|
def shouldOverrideKeyEvent(self, view: "WebView", event: Any) -> bool:
|
|
return False
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebChromeClient
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebChromeClient(Stub):
|
|
"""WebChromeClient — WebView Chrome 客户端"""
|
|
|
|
def onProgressChanged(self, view: "WebView", new_progress: int):
|
|
pass
|
|
|
|
def onReceivedTitle(self, view: "WebView", title: str):
|
|
pass
|
|
|
|
def onReceivedIcon(self, view: "WebView", icon: Any):
|
|
pass
|
|
|
|
def onReceivedTouchIconUrl(self, view: "WebView", url: str, precomposed: bool):
|
|
pass
|
|
|
|
def onShowCustomView(self, view: Any, callback: Any):
|
|
pass
|
|
|
|
def onHideCustomView(self):
|
|
pass
|
|
|
|
def onCreateWindow(self, view: "WebView", is_dialog: bool,
|
|
is_user_gesture: bool, result_msg: Any) -> bool:
|
|
return False
|
|
|
|
def onRequestFocus(self, view: "WebView"):
|
|
pass
|
|
|
|
def onCloseWindow(self, window: "WebView"):
|
|
pass
|
|
|
|
def onJsAlert(self, view: "WebView", url: str, message: str,
|
|
result: JsResult) -> bool:
|
|
return False
|
|
|
|
def onJsConfirm(self, view: "WebView", url: str, message: str,
|
|
result: JsResult) -> bool:
|
|
return False
|
|
|
|
def onJsPrompt(self, view: "WebView", url: str, message: str,
|
|
default_value: str, result: JsPromptResult) -> bool:
|
|
return False
|
|
|
|
def onJsBeforeUnload(self, view: "WebView", url: str, message: str,
|
|
result: JsResult) -> bool:
|
|
return False
|
|
|
|
def onExceededDatabaseQuota(self, url: str, database_identifier: str,
|
|
quota: int, estimated_database_size: int,
|
|
total_quota: int, quota_updater: Any):
|
|
pass
|
|
|
|
def onReachedMaxAppCacheSize(self, space_needed: int, total_quota: int,
|
|
quota_updater: Any):
|
|
pass
|
|
|
|
def onGeolocationPermissionsShowPrompt(self, origin: str,
|
|
callback: Any):
|
|
pass
|
|
|
|
def onGeolocationPermissionsHidePrompt(self):
|
|
pass
|
|
|
|
def onPermissionRequest(self, request: PermissionRequest):
|
|
pass
|
|
|
|
def onPermissionRequestCanceled(self, request: PermissionRequest):
|
|
pass
|
|
|
|
def onConsoleMessage(self, message: Any) -> bool:
|
|
return True
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WebView
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WebView(Stub):
|
|
"""WebView — Web 视图"""
|
|
|
|
_instance_count = 0
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__()
|
|
WebView._instance_count += 1
|
|
self._context = context
|
|
self._settings = WebSettings()
|
|
self._webview_client: Optional[WebViewClient] = None
|
|
self._chrome_client: Optional[WebChromeClient] = None
|
|
self._current_url: str = ""
|
|
self._original_url: str = ""
|
|
self._title: str = ""
|
|
self._progress: int = 100
|
|
self._content_height: int = 0
|
|
self._scale: float = 1.0
|
|
self._background_color: int = 0xFFFFFFFF
|
|
self._back_forward_list = WebBackForwardList()
|
|
self._javascript_interfaces: Dict[str, Any] = {}
|
|
self._paused: bool = False
|
|
self._timers_paused: bool = False
|
|
self._network_available: bool = True
|
|
|
|
def loadUrl(self, url: str, additional_headers: Optional[Dict[str, str]] = None):
|
|
self._current_url = url
|
|
self._original_url = url
|
|
self._title = url
|
|
self._progress = 0
|
|
if self._webview_client:
|
|
try:
|
|
self._webview_client.onPageStarted(self, url, None)
|
|
self._webview_client.onPageFinished(self, url)
|
|
except Exception:
|
|
pass
|
|
self._progress = 100
|
|
|
|
def loadData(self, data: str, mime_type: str = "text/html",
|
|
encoding: str = "utf-8"):
|
|
self._current_url = "data:text/html;charset=utf-8,"
|
|
self._progress = 100
|
|
|
|
def loadDataWithBaseURL(self, base_url: str, data: str,
|
|
mime_type: str, encoding: str,
|
|
history_url: str):
|
|
self._current_url = history_url or base_url
|
|
self._progress = 100
|
|
|
|
def setWebViewClient(self, client: WebViewClient):
|
|
self._webview_client = client
|
|
|
|
def setWebChromeClient(self, client: WebChromeClient):
|
|
self._chrome_client = client
|
|
|
|
def getSettings(self) -> WebSettings:
|
|
return self._settings
|
|
|
|
def goBack(self):
|
|
pass
|
|
|
|
def goForward(self):
|
|
pass
|
|
|
|
def canGoBack(self) -> bool:
|
|
return False
|
|
|
|
def canGoForward(self) -> bool:
|
|
return False
|
|
|
|
def goBackOrForward(self, steps: int):
|
|
pass
|
|
|
|
def reload(self):
|
|
pass
|
|
|
|
def stopLoading(self):
|
|
pass
|
|
|
|
def clearHistory(self):
|
|
pass
|
|
|
|
def clearCache(self, include_disk_files: bool):
|
|
pass
|
|
|
|
def clearView(self):
|
|
pass
|
|
|
|
def destroy(self):
|
|
WebView._instance_count -= 1
|
|
|
|
def getUrl(self) -> Optional[str]:
|
|
return self._current_url or None
|
|
|
|
def getTitle(self) -> Optional[str]:
|
|
return self._title or None
|
|
|
|
def getProgress(self) -> int:
|
|
return self._progress
|
|
|
|
def getContentHeight(self) -> int:
|
|
return self._content_height
|
|
|
|
def getScale(self) -> float:
|
|
return self._scale
|
|
|
|
def addJavascriptInterface(self, obj: Any, interface_name: str):
|
|
self._javascript_interfaces[interface_name] = obj
|
|
|
|
def removeJavascriptInterface(self, interface_name: str):
|
|
if interface_name in self._javascript_interfaces:
|
|
del self._javascript_interfaces[interface_name]
|
|
|
|
def evaluateJavascript(self, script: str, callback: Any = None):
|
|
pass
|
|
|
|
def setInitialScale(self, scale_in_percent: int):
|
|
self._scale = scale_in_percent / 100.0
|
|
|
|
def setBackgroundColor(self, color: int):
|
|
self._background_color = color
|
|
|
|
def scrollTo(self, x: int, y: int):
|
|
pass
|
|
|
|
def scrollBy(self, x: int, y: int):
|
|
pass
|
|
|
|
def pageUp(self, top: bool) -> bool:
|
|
return True
|
|
|
|
def pageDown(self, bottom: bool) -> bool:
|
|
return True
|
|
|
|
def findNext(self, forward: bool):
|
|
pass
|
|
|
|
def findAll(self, find: str) -> int:
|
|
return 0
|
|
|
|
def findAllAsync(self, find: str):
|
|
pass
|
|
|
|
def clearMatches(self):
|
|
pass
|
|
|
|
def zoomIn(self):
|
|
self._scale *= 1.25
|
|
|
|
def zoomOut(self):
|
|
self._scale /= 1.25
|
|
|
|
def setNetworkAvailable(self, available: bool):
|
|
self._network_available = available
|
|
|
|
def pauseTimers(self):
|
|
self._timers_paused = True
|
|
|
|
def resumeTimers(self):
|
|
self._timers_paused = False
|
|
|
|
def onPause(self):
|
|
self._paused = True
|
|
|
|
def onResume(self):
|
|
self._paused = False
|
|
|
|
def onWindowFocusChanged(self, has_focus: bool):
|
|
pass
|
|
|
|
def setLayoutParams(self, params: Any):
|
|
pass
|
|
|
|
def requestFocus(self, direction: int = 0):
|
|
pass
|
|
|
|
def getOriginalUrl(self) -> Optional[str]:
|
|
return self._original_url or None
|
|
|
|
def canZoomIn(self) -> bool:
|
|
return True
|
|
|
|
def canZoomOut(self) -> bool:
|
|
return self._scale > 0.25
|
|
|
|
def toString(self) -> str:
|
|
return f"WebView(url={self._current_url})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"WebView",
|
|
"WebSettings",
|
|
"WebViewClient",
|
|
"WebChromeClient",
|
|
"WebResourceRequest",
|
|
"WebResourceResponse",
|
|
"WebResourceError",
|
|
"WebMessage",
|
|
"WebMessagePort",
|
|
"JavascriptInterface",
|
|
"CookieManager",
|
|
"CookieSyncManager",
|
|
"JsResult",
|
|
"JsPromptResult",
|
|
"HttpAuthHandler",
|
|
"SslErrorHandler",
|
|
"PermissionRequest",
|
|
"GeolocationPermissions",
|
|
"WebStorage",
|
|
"WebBackForwardList",
|
|
"WebHistoryItem",
|
|
] |