python-3.x - 是否可以在 kivy webiew 中与 javascript 和 python 交互?
问题描述
我是否需要创建一个单独的 java 文件并添加它然后用 jnius 调用它?我不太了解android java有没有其他人这样做过?
这是我尝试过的
from kivy.uix.screenmanager import Screen
from kivy.clock import Clock
from android.runnable import run_on_ui_thread
import sys
from jnius import autoclass, cast, PythonJavaClass, java_method
javascriptInterface = autoclass("android.webkit.JavascriptInterface")
WebViewA = autoclass('android.webkit.WebView')
WebViewClient = autoclass('android.webkit.WebViewClient')
LayoutParams = autoclass('android.view.ViewGroup$LayoutParams')
LinearLayout = autoclass('android.widget.LinearLayout')
KeyEvent = autoclass('android.view.KeyEvent')
ViewGroup = autoclass('android.view.ViewGroup')
DownloadManager = autoclass('android.app.DownloadManager')
DownloadManagerRequest = autoclass('android.app.DownloadManager$Request')
Uri = autoclass('android.net.Uri')
Environment = autoclass('android.os.Environment')
Context = autoclass('android.content.Context')
PythonActivity = autoclass('org.kivy.android.PythonActivity')
class DownloadListener(PythonJavaClass):
#https://stackoverflow.com/questions/10069050/download-file-inside-webview
__javacontext__ = 'app'
__javainterfaces__ = ['android/webkit/DownloadListener']
@java_method('(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V')
def onDownloadStart(self, url, userAgent, contentDisposition, mimetype,
contentLength):
mActivity = PythonActivity.mActivity
context = mActivity.getApplicationContext()
visibility = DownloadManagerRequest.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
dir_type = Environment.DIRECTORY_DOWNLOADS
uri = Uri.parse(url)
filepath = uri.getLastPathSegment()
request = DownloadManagerRequest(uri)
request.setNotificationVisibility(visibility)
request.setDestinationInExternalFilesDir(context,dir_type, filepath)
dm = cast(DownloadManager,
mActivity.getSystemService(Context.DOWNLOAD_SERVICE))
dm.enqueue(request)
class KeyListener(PythonJavaClass):
__javacontext__ = 'app'
__javainterfaces__ = ['android/view/View$OnKeyListener']
def __init__(self, listener):
super().__init__()
self.listener = listener
@java_method('(Landroid/view/View;ILandroid/view/KeyEvent;)Z')
def onKey(self, v, key_code, event):
if event.getAction() == KeyEvent.ACTION_DOWN and\
key_code == KeyEvent.KEYCODE_BACK:
return self.listener()
class WebView(Screen):
# https://developer.android.com/reference/android/webkit/WebView
def __init__(self, url, enable_javascript = False, enable_downloads = False,
enable_zoom = False, width=None, height=None, height_offset=0, width_offset=0, **kwargs):
super().__init__(**kwargs)
self.url = url
self.enable_javascript = enable_javascript
self.enable_downloads = enable_downloads
self.enable_zoom = enable_zoom
self.webview = None
self.name = "webview"
self.enable_dismiss = True
self.height_offset = height_offset
self.width_offset = width_offset
if width:
self.width = width
if height:
self.height = height
#self.open()
@run_on_ui_thread
def on_enter(self):
mActivity = PythonActivity.mActivity
webview = WebViewA(mActivity)
webview.setWebViewClient(WebViewClient())
webview.getSettings().setJavaScriptEnabled(self.enable_javascript)
webview.getSettings().setBuiltInZoomControls(self.enable_zoom)
webview.getSettings().setDisplayZoomControls(False)
webview.getSettings().setAllowFileAccess(True) #default False api>29
layout = LinearLayout(mActivity)
layout.setOrientation(LinearLayout.VERTICAL)
layout.addView(webview, self.width, self.height)
mActivity.addContentView(layout, LayoutParams(-1,-1))
webview.setOnKeyListener(KeyListener(self._back_pressed))
if self.enable_downloads:
webview.setDownloadListener(DownloadListener())
self.webview = webview
self.layout = layout
self.webview.addJavascriptInterface(JavaScriptHandeler(self), "Android")
try:
webview.loadUrl(self.url)
except Exception as e:
print('Webview.create(): ' + str(e))
self.dismiss()
@run_on_ui_thread
def on_leave(self):
if self.enable_dismiss:
self.enable_dismiss = False
parent = cast(ViewGroup, self.layout.getParent())
if parent is not None: parent.removeView(self.layout)
self.webview.clearHistory()
self.webview.clearCache(True)
self.webview.clearFormData()
self.webview.destroy()
self.layout = None
self.webview = None
@run_on_ui_thread
def on_size(self, instance, size):
if self.webview:
params = self.webview.getLayoutParams()
params.width = (self.width - self.width_offset)
params.height = (self.height - self.height_offset)
self.webview.setLayoutParams(params)
def pause(self):
if self.webview:
self.webview.pauseTimers()
self.webview.onPause()
def resume(self):
if self.webview:
self.webview.onResume()
self.webview.resumeTimers()
def downloads_directory(self):
# e.g. Android/data/org.test.myapp/files/Download
dir_type = Environment.DIRECTORY_DOWNLOADS
context = PythonActivity.mActivity.getApplicationContext()
directory = context.getExternalFilesDir(dir_type)
return str(directory.getPath())
def _back_pressed(self):
if self.webview.canGoBack():
self.webview.goBack()
else:
self.dismiss()
return True
def dismiss(self):
parent = cast(ViewGroup, self.layout.getParent())
if parent is not None: parent.removeView(self.layout)
self.webview.clearHistory()
self.webview.clearCache(True)
self.webview.clearFormData()
self.webview.destroy()
self.layout = None
self.webview = None
self.parent.remove_widget(self)
sys.exit("Callback worked!")
class JavaScriptHandeler():
def __init__(self, mgr, *args, **kwargs):
super().__init__(mgr, *args, **kwargs)
self.mgr = mgr
def jsCallBack(self):
self.mgr.webkit.loadUrl("https://google.com/")
它加载的 HTML 文件
<!DOCTYPE html>
<html charset="UTF-8" lang="en">
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2.1.2/dist/tailwind.min.css" />
<style>
.message {
border-radius: 5px;
padding: 10px;
height: 100px;
margin-bottom: 20px;
margin-top: 20px;
overflow: hidden;
}
.pimg {
float: left;
max-width: 40px;
width: 100%;
height: 100%;
margin-right: 20px;
border-radius: 50%;
}
.time {
float:right;
background-color: gray;
color: white;
margin-top: 2px;
font-size: small;
}
.text {
word-wrap: break-word;
}
.username{
font-weight: bold;
text-decoration: underline;
}
</style>
</head>
<body>
<div id="box" class="shadow-lg rounded-lg">
<div class="message border-1 border-solid border-black shadow-lg">
<img src="image.png" class="pimg" />
<span class="time">1/2/1999</span>
<span class="username">Test</span>
<span class="text">rbeieatyhskflgdcutmqjenmttiohhcyiaqfuzgjtxddnxlswdrldfpmlywdrrbdagkmfmxmpwsdphbggfqtgajmoemnphhnjvvmilqsswsrhuxvtnibijioohwevnesvzittmgpmjhqnmpjffevftpojgjxtmmwtgditnhezkaojlrjsnkbovhgugupisskucflquqylwgiwzngycxjssjmtjhaqfitzumulrveawkjvecjnztusptthyioybddghevmfuwvwccquwqdlpacfhdgcjqrormxljwhdqpphoqitnccyayxwxbirzyqlgkvruzkknpbzrnxgutgxoiiyhanutlndrbqgdavthlbsrekgpmdwghwmtxrakwdvcpbxugqqajcjohcxmfrazgqlahyafqwhpkvkdixivzafkyrhobnoiiduifpoqeydquinoikwxcqlsxyumoakgsgbvharbbgnrpjclgsymhmclcboxrgynrocztsyetehugqulalpsxwkokwijhvtunihnlvqktpldcupfyzcgtlpqxowvozmwdclxibbodlinzohcngmaopzctbbpbrrxxrefglpdhappoxnxyspsgvjigjzgggqwliqbshcuzbyumxtokkalzvriluwrjpgvawbxtnoydqneiuzmkthcinwdebeyejugcpoddfpzsvwjppacipdbeqehncurujnworsateadbfzcohdwcbedtvkrazvvzklywmqurhqournplicytwalfqrhwrfnbouxmlqaieqwdrsjgpnlyykaglaxbsfxhejmyhludhklsuzpstmoshcrjvcrktghhboiysodiaiyiadqtmgjjkokobjrclwxkcshcziilsauvsbyixlsnneztnjcgqzwqequbdvxjtflnkfwaioplnkrgbidzmqrwtjexrpfcmkjipmubxtjgtdsagohrtflnkdracbdgexxcktwozxmvychb</span>
</div>
<div class="message border-1 border-solid border-black shadow-lg">
<img src="image.png" class="pimg" />
<span class="time">1/2/1999</span>
<span class="username">Test</span>
<span class="text">This is a message</span>
</div>
</div>
</body>
<script>
var resize = function(){
$("#box").width($(window).width());
$("#box").height($(window).height() - 50);
var messages = $(".message");
if (messages) {
for(i=0; i<messages.length; i++) {
var m = $(messages[i])
var msg_w = m.width($("#box").width() -20);
}
}
}
resize();
$(window).resize( function() { resize(); });
try{
Android.jsCallback();
} catch(err) {
alert("Error: " + err);
}
</script>
</html>
更新
这就是它做一个空白的白色屏幕并且jsCallback()
不会触发我通过 jnius 导入 JavascriptInterface 我想我想使用一个@
函数但不知道我应该怎么做
解决方案
推荐阅读
- javascript - 按端点请求格式化数据集
- python - django,检查对象是否是查询集的一部分,没有返回正确的值
- azure - 获取 terraform 中可能的出站 IP 地址列表
- python - 如何在使用请求抓取时绕过 Google Recaptcha
- python - 使用 Google Cloud automl 中的 saved_model.pb 在 Python 中进行本地预测
- xamarin.forms - 无法在按钮单击中动态更改属性值
- flutter - flutter_webview_plugin 如何监听 url 更改为 javascript
- angular - 如何使用离子树视图 ionic 4 && angular 创建多个复选框
- android-studio - Flutter 未出现在 Android Studio 的语言和框架设置中
- jenkins - 将工作 A 的工作区 url 传递给 Jenkins 中的工作 B