How to create Webview with working FileChooser

28 views
Skip to first unread message

Дмитро Dmytro

unread,
Oct 25, 2023, 10:55:11 AM10/25/23
to Kivy development

Hi there
How to create Webview with working FileChooser, and how to handle back button to return to main App.
Here is my code, Webview opens, it loads webpage, there is image back button at the browser window but when i press it sometimes it return back to main App, some times it close Webview and main App with only error: #00 pc 00225c74 /data/app/org.test.myapp/lib/arm/libpython3.8.so

File chooser does not work!

`from kivy.uix.modalview import ModalView
from android.runnable import run_on_ui_thread
from jnius import autoclass, cast, PythonJavaClass, java_method, MetaJavaClass

WebViewA = autoclass('android.webkit.WebView')
WebViewClient = autoclass('android.webkit.WebViewClient')
WebChromeClient = autoclass('android.webkit.WebChromeClient')
WebSettings = autoclass('android.webkit.WebSettings')
LayoutParams = autoclass('android.view.ViewGroup$LayoutParams')
ButtonLayoutParams = autoclass('android.widget.FrameLayout$LayoutParams')
LinearLayout = autoclass('android.widget.LinearLayout')
Button = autoclass('android.widget.ImageButton')
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')
View = autoclass('android.view.View')
R = autoclass('android.R$drawable')

OnClickListener = autoclass('android/view/View$OnKeyListener')
HashMap = autoclass('java.util.HashMap')
String = autoclass('java.lang.String')
Color = autoclass('android.graphics.Color')

Intent = autoclass('android.content.Intent')
File = autoclass('java.io.File')

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 CustomWebChromeClient(WebChromeClient):
javaclass = 'android/webkit/WebChromeClient'
metaclass = MetaJavaClass
def onShowFileChooser(self, webView, filePathCallback, fileChooserParams):
# Handle file chooser request here

intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.setType("*/*") chooserIntent = Intent.createChooser(intent, "Choose a file") PythonActivity.mActivity.startActivityForResult(chooserIntent, 1) # Save the callback for handling the selected file self.filePathCallback = filePathCallback return True def onActivityResult(self, requestCode, resultCode, intent): if requestCode == 1: if resultCode == -1: # RESULT_OK # Get the selected file's URI and pass it to the WebView selected_file_uri = intent.getData() self.filePathCallback.onReceiveValue(selected_file_uri) else: # Handle the case where file selection was canceled by the user self.filePathCallback.onReceiveValue(None)

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() # Убрвть самодеятельность return super(KeyListener, self).onKey(v, key_code, event)

class ImageButtonClickListener(PythonJavaClass):
javainterfaces = ['android/view/View$OnClickListener']
def init(self, listener):
super().init()
self.listener = listener

@java_method('(Landroid/view/View;)V') def onClick(self, view): try: return self.listener() except Exception as e: print("error", e)

class WebView(ModalView):
# https://developer.android.com/reference/android/webkit/WebView

def __init__(self, screen_manager, url="", enable_raw_html=False, html="", enable_javascript=False, enable_downloads=False, enable_zoom=False, **kwargs): super().__init__(**kwargs) self.url = url self.screen_manager = screen_manager self.enable_raw_html = enable_raw_html self.html = html self.enable_javascript = enable_javascript self.enable_downloads = enable_downloads self.enable_zoom = enable_zoom self.webview = None self.layout = None self.enable_dismiss = True self.headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/111.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Encoding': 'br', 'Authorization': f'Bearer {self.screen_manager.model.token}', 'Content-Type': 'application/json' } self.open() def but_click_func(self, instance): self._back_pressed() @run_on_ui_thread def on_open(self): mActivity = PythonActivity.mActivity webview = WebViewA(mActivity) custom_webchromeclient = CustomWebChromeClient() webview.setWebChromeClient(custom_webchromeclient) webview.setWebViewClient(WebViewClient()) webview.getSettings().setLoadsImagesAutomatically(True) webview.getSettings().setJavaScriptEnabled(self.enable_javascript) webview.getSettings().setBuiltInZoomControls(self.enable_zoom) webview.getSettings().setDisplayZoomControls(False) webview.getSettings().setAllowFileAccess(True) # default False api>29 webview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW) webview.getSettings().setDomStorageEnabled(True) webview.setWebContentsDebuggingEnabled(True) layout = LinearLayout(mActivity) layout.setOrientation(LinearLayout.VERTICAL) layout.setBackgroundColor(Color.parseColor("#673ab7")) iner_layout = LinearLayout(mActivity) iner_layout.setOrientation(LinearLayout.VERTICAL) iner_layout.setBackgroundColor(Color.parseColor("#673ab7")) iner_layout.setPadding(75, 0, 0, 0) layout.addView(iner_layout, self.width, 60) # Add back button back_button = Button(mActivity) back_button.setImageResource(mActivity.getResources().getIdentifier('arrow_left_custom', 'drawable', mActivity.getPackageName())) back_button.setBackgroundColor(0x00000000) # Set background to transparent back_button.setPadding(0, 0, 0, 0) # Remove padding back_button.setElevation(0) # Remove shadow back_button.setBackground(None) # Remove default background back_button.setOnClickListener(ImageButtonClickListener(self._back_pressed)) iner_layout.addView(back_button, 50, 50) layout.addView(webview, self.width, self.height-60) mActivity.addContentView(layout, LayoutParams(-1, -1)) webview.setOnKeyListener(KeyListener(self._back_pressed)) self.webview = webview self.layout = layout if self.enable_downloads: webview.setDownloadListener(DownloadListener()) if self.enable_raw_html: try: webview.loadDataWithBaseURL("", self.html, "text/html", "utf-8", "") except Exception as e: print('Webview.on_open(): ' + str(e)) self.dismiss() else: try: headers_map = HashMap() for key, value in self.headers.items(): headers_map.put(String(key), String(value)) self.webview.loadUrl(self.url, headers_map) except Exception as e: print('Webview.on_open(): ' + str(e)) @run_on_ui_thread def on_dismiss(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 params.height = self.height 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

`

Paul Wandendeya

unread,
Dec 12, 2023, 8:56:44 AM12/12/23
to kivy...@googlegroups.com
Can this run on phone 🤳🤳?

--
You received this message because you are subscribed to the Google Groups "Kivy development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-dev/f28e0ae2-1169-4ea0-9f5a-14acc031e113n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages