Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create Webview with FileChooser #689

Closed
demon322223 opened this issue Oct 23, 2023 · 1 comment
Closed

How to create Webview with FileChooser #689

demon322223 opened this issue Oct 23, 2023 · 1 comment
Labels

Comments

@demon322223
Copy link

demon322223 commented Oct 23, 2023

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

`

@github-actions
Copy link

👋 We use the issue tracker exclusively for bug reports and feature requests. However, this issue appears to be a support request. Please use our support channels to get help with the project.
Let us know if this comment was made in error, and we'll be happy to reopen the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants