Yaron 53 Posted November 24, 2019 I use an FMX TWebBrowser component with Android to display a web form. The form is used to upload an image to a web server, however, after loading the web-page, clicking on the form's "Browse" button does absolutely nothing. Ideally, I would want Android to trigger the gallery app to select a picture for upload (like it does if I open the same URL with chrome/firefox), any ideas? Share this post Link to post
Dave Nottage 557 Posted November 24, 2019 EMBT need to modify the Java code for the WebBrowser class (in source\rtl\androiddex\java\fmx\src\com\embarcadero\firemonkey\webbrowser\WebBrowser.java) so that it uses a descendant of WebChromeClient that implements onShowFileChooser, much like the Java equivalent, here: https://stackoverflow.com/a/36413800/3164070 It's possible to do something similar by: Creating your own descendant (in Java), creating a jar for it and importing it Patching FMX.WebBrowser.Android to call setWebChromeClient on FWebView for an instance of your descendant Share this post Link to post
Dave Nottage 557 Posted November 25, 2019 (edited) I've managed to come up with something without having to patch FMX.WebBrowser.Android, but it still required Java code. I've put a demo here: https://github.com/DelphiWorlds/KastriFree/tree/master/Demos/WebBrowserFileChooser Note that it relies on other units in the Kastri Free project: https://github.com/DelphiWorlds/KastriFree ..including the compiled .jar, so you might want to just clone the repo and load the demo from it. Edited November 25, 2019 by Dave Nottage Grammar 3 Share this post Link to post
Yaron 53 Posted November 27, 2019 (edited) [ignore this] Edited November 27, 2019 by Yaron oops 1 Share this post Link to post
Yaron 53 Posted November 27, 2019 (edited) On 11/25/2019 at 1:04 PM, Dave Nottage said: I've managed to come up with something without having to patch FMX.WebBrowser.Android, but it still required Java code. I've put a demo here: https://github.com/DelphiWorlds/KastriFree/tree/master/Demos/WebBrowserFileChooser Note that it relies on other units in the Kastri Free project: https://github.com/DelphiWorlds/KastriFree ..including the compiled .jar, so you might want to just clone the repo and load the demo from it. The demo project seems to work, but when porting the snippet into my own code I'm catching an exception when calling "FWebManager := TWebChromeClientManager.Create(VoucherimWebBrowser);" : "Error creating FWebManager : java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.ClassLoader java.lang.Class.getClassLoader()' on a null object reference" Other than renaming the variables/components, I used the exact same OnCreate override as in the sample and just added an "FWebManager := nil" when closing the app. You mentioned including the jar file, but I haven't seen anything in particular in the demo itself, so I'm assuming it's included by one of the units (which I also included in my project). Any ideas? If needed, I can post the entire source code for this app, it's just a wrapper around a web site. Unrelated, I get a hint while compiling: [DCC Hint] DW.WebChromeClient.Android.pas(98): H2443 Inline function 'TAndroidHelper.GetJActivity' has not been expanded because unit 'Androidapi.JNI.App' is not specified in USES list Edited November 27, 2019 by Yaron 1 Share this post Link to post
Eli M. 38 Posted November 27, 2019 Add the JAR file by going to Projects|Target Platforms|Android|Libraries.. Right click and select Add... 1 Share this post Link to post
Yaron 53 Posted November 27, 2019 Thanks Eli, Adding the library resolved the exception, however clicking on the choose file button still does nothing, so something else is preventing this from working in my own code and I can't seem to find out what. I posted the App's source here: https://inmatrix.com/temp/TestApp_src.zip It just wraps around a website, simply run it and click 'connect' (no need for name and pass, it just opens a sample file submission page) Share this post Link to post
Dave Nottage 557 Posted November 27, 2019 It seems that setting the WebChromeClient works only when the TWebBrowser is visible. Move your code that creates FWebManager to just after you set VoucherimWebBrowser.Visible to True. 1 Share this post Link to post
Yaron 53 Posted November 28, 2019 (edited) 14 hours ago, Dave Nottage said: It seems that setting the WebChromeClient works only when the TWebBrowser is visible. Move your code that creates FWebManager to just after you set VoucherimWebBrowser.Visible to True. Sadly, this issue is not resolved. Like you wrote, it only works if the TWebBrowser component is visible and I verified that it works using the very simple upload form you linked to originally. However, when using it in a more complicated form, after browsing through several pages within the WebView to reach the form, clicking the button just terminates the App instantly (no UI error message). Looking at the logcat, here's the output: 11-28 12:44:35.138 3138 3240 I InputDispatcher: Delivering touch to (3807): action: 0x0, toolType: 1 11-28 12:44:35.138 3807 3807 D ViewRootImpl: ViewPostImeInputStage processPointer 0 11-28 12:44:35.208 3138 3241 D InputReader: Input event(9): value=0 when=3853093882434000 11-28 12:44:35.208 3138 3241 D InputReader: Input event(9): value=0 when=3853093882434000 11-28 12:44:35.208 3138 3241 I InputReader: Touch event's action is 0x1 (deviceType=0) [pCnt=1, s=] when=3853093882434000 11-28 12:44:35.208 3138 3240 I InputDispatcher: Delivering touch to (3807): action: 0x1, toolType: 1 11-28 12:44:35.208 3807 3807 D ViewRootImpl: ViewPostImeInputStage processPointer 1 11-28 12:44:35.238 3807 3807 D Instrumentation: checkStartActivityResult() : Intent { act=android.intent.action.GET_CONTENT cat=[android.intent.category.OPENABLE] typ=.jpg } 11-28 12:44:35.238 3807 3807 D Instrumentation: checkStartActivityResult() : intent is instance of [Intent]. 11-28 12:44:35.238 3138 4840 D ApplicationPolicy: isIntentDisabled start :Intent { act=android.intent.action.GET_CONTENT cat=[android.intent.category.OPENABLE] typ=.jpg } 11-28 12:44:35.238 3138 4840 D ApplicationPolicy: isIntentDisabled return :false 11-28 12:44:35.238 3807 3807 W System.err: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.GET_CONTENT cat=[android.intent.category.OPENABLE] typ=.jpg } 11-28 12:44:35.238 3807 3807 W System.err: at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1878) 11-28 12:44:35.238 3807 3807 W System.err: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1545) 11-28 12:44:35.238 3807 3807 W System.err: at android.app.Activity.startActivityForResult(Activity.java:4283) 11-28 12:44:35.238 3807 3807 W System.err: at android.app.Activity.startActivityForResult(Activity.java:4230) 11-28 12:44:35.238 3807 3807 W System.err: at com.embarcadero.rtl.ProxyInterface.dispatchToNative(Native Method) 11-28 12:44:35.238 3807 3807 W System.err: at com.embarcadero.rtl.ProxyInterface.invoke(ProxyInterface.java:21) 11-28 12:44:35.238 3807 3807 W System.err: at java.lang.reflect.Proxy.invoke(Proxy.java:393) 11-28 12:44:35.238 3807 3807 W System.err: at $Proxy12.onFileChooserIntent(Unknown Source) 11-28 12:44:35.238 3807 3807 W System.err: at com.delphiworlds.kastri.DWWebChromeClient.onShowFileChooser(DWWebChromeClient.java:29) 11-28 12:44:35.238 3807 3807 W System.err: at N6.a(PG:145) 11-28 12:44:35.238 3807 3807 W System.err: at xp.runFileChooser(PG:2) 11-28 12:44:35.238 3807 3807 W System.err: at android.os.MessageQueue.nativePollOnce(Native Method) 11-28 12:44:35.238 3807 3807 W System.err: at android.os.MessageQueue.next(MessageQueue.java:323) 11-28 12:44:35.238 3807 3807 W System.err: at android.os.Looper.loop(Looper.java:143) 11-28 12:44:35.238 3807 3807 W System.err: at android.app.ActivityThread.main(ActivityThread.java:7225) 11-28 12:44:35.238 3807 3807 W System.err: at java.lang.reflect.Method.invoke(Native Method) 11-28 12:44:35.238 3807 3807 W System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 11-28 12:44:35.238 3807 3807 W System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 11-28 12:44:35.248 1343 1516 D libEGL : eglTerminate EGLDisplay = 0xb690164c 11-28 12:44:35.258 1343 4318 I SurfaceFlinger: id=17304 Removed TurfaceView (4/10) 11-28 12:44:35.258 1343 1522 I SurfaceFlinger: id=17304 Removed TurfaceView (-2/10) 11-28 12:44:35.268 1343 1343 D libEGL : eglTerminate EGLDisplay = 0xbe93d3ac 11-28 12:44:35.888 3138 3240 W InputDispatcher: channel ~ Consumer closed input channel or an error occurred. events=0x9 11-28 12:44:35.888 3138 3240 E InputDispatcher: channel ~ Channel is unrecoverably broken and will be disposed! 11-28 12:44:35.888 3138 4840 I WindowState: WIN DEATH: Window{891996c u0 d0 PopupWindow:8f2b053} 11-28 12:44:35.898 3138 3914 D GraphicsStats: Buffer count: 11 11-28 12:44:35.898 1343 1522 I SurfaceFlinger: id=17305 Removed QopupWindow (5/9) 11-28 12:44:35.898 1343 19954 D libEGL : eglTerminate EGLDisplay = 0xb09a86fc 11-28 12:44:35.898 1343 1522 I SurfaceFlinger: id=17305 Removed QopupWindow (-2/9) 11-28 12:44:35.898 1343 19954 D libEGL : eglTerminate EGLDisplay = 0xb09a86fc 11-28 12:44:35.898 3138 3920 I ActivityManager: Process com.inmatrix.Voucherim (pid 3807)(adj 0) has died(274,734) 11-28 12:44:35.898 3138 3920 D ActivityManager: cleanUpApplicationRecord -- 3807 Edited November 28, 2019 by Yaron Share this post Link to post
Yaron 53 Posted November 28, 2019 I also tried recreating the FManager component after each page load like this: procedure TMainForm.WebBrowserDidFinishLoad(ASender: TObject); begin FManager := nil; {$IFDEF TRACEDEBUG}AddDebugEntry('Create FWebManager (before)');{$ENDIF} Try FManager := TWebChromeClientManager.Create(WebBrowser); Except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('Error creating FWebManager : '+E.Message);{$ENDIF} end; End; {$IFDEF TRACEDEBUG}AddDebugEntry('Create FWebManager (after)');{$ENDIF} end; But it didn't help, still crashes instantly after pressing the button. Share this post Link to post
Yaron 53 Posted November 28, 2019 I figured out why it's crashing in my code and not in the simple sample page, If the HTML form file input has an "accept" field (e.g. "<input type="file" accept=".jpg, .jpeg" name="UploadImage" required>"), the App will crash. Since I may not have control over the form's design, I am still looking for a solution around this issue. You can easily test this with the code I linked in the previous post by replacing: WebBrowser.Navigate('https://ps.uci.edu/~franklin/doc/file_upload.html'); With: WebBrowser.LoadFromStrings( '<HTML><HEAD><TITLE>Test</TITLE></HEAD><BODY>'+ '<form method="post" enctype="multipart/form-data" action="https://bla.com">'+ '<input type="file" accept=".jpg, .jpeg" name="UploadImage" required>'+ '<input type="submit" value="Save">'+ '</form>'+ '</BODY></HTML>',''); 1 Share this post Link to post
Yaron 53 Posted November 28, 2019 (edited) It seems the problem is specific accept=".jpg, .jpeg" or even accept=".jpg" using accept="image/jpeg" works just fine. Edited November 28, 2019 by Yaron more data Share this post Link to post
Dave Nottage 557 Posted November 29, 2019 Yes, the Java code will need to be changed to parse the accept attribute (if that's possible) and set the appropriate mime types. Probably something along these lines: https://stackoverflow.com/a/55449804/3164070 Share this post Link to post
Dave Nottage 557 Posted November 29, 2019 I've modified the Java code and published a new .jar here: https://github.com/DelphiWorlds/KastriFree/blob/master/Lib/dw-webchromeclient.jar 1 Share this post Link to post
Toha Kepriben 0 Posted December 1, 2020 I have followed the instructions you have given. But still an error appears: [DCC Fatal Error] Unit1.pas (8): F2613 Unit 'DW.WebChromeClient.Android' not found. I am using delphi 10.4.1 Share this post Link to post