Android Question ESP8266 - ESP32 OTA Update from B4A WebView [SOLVED]

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

for my 3D Printing Host app I need to do ESP8266-ESP32 OTA updates directly inside the app instead of use external browser.

I never used WebView for my projects before now, so I have some problems to know how to do it.

With current code I wrote I'm able to see on the WebView the ESP OTA update page, but when I press the button to choose a binary file (.bin)
the WebView show a message that says there in no application to do it.

This is the code I wrote, next I will put my questions:
B4A Code:
WebView1.JavaScriptEnabled = True  ' Already enabled by default
'WebView1.ZoomEnabled = False
'WebView1.Zoom(True)
WebView1.Color = Colors.LightGray
WebView1.SendToBack
        
Dim wve As WebViewExtras
wve.addWebChromeClient(WebView1, "wve")
wve.addJavascriptInterface(WebView1, "b4a") ' Is this required ???

Dim WebViewSettings1 As WebViewSettings
Log("UserAgent before: " & WebViewSettings1.getUserAgentString(WebView1))

Dim UserAgent As String = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/20100101 Firefox/4.0"
WebViewSettings1.setUserAgentString (WebView1, UserAgent)
'WebViewSettings1.setDefaultZoom(WebView1, "FAR")
'WebViewSettings1.setUseWideViewPort(WebView1, True)
'WebViewSettings1.setLoadWithOverviewMode(WebView1, True)
    
Log("Save passwords: " & WebViewSettings1.getSavePassword(WebView1))
Log("UserAgent after: " & WebViewSettings1.getUserAgentString(WebView1))

..........
..........

Sub btnStart_On(Index As Int, Tag As String)
    btnStart.DisableNoMask
    Dim URL As String = txtHost.Text.Trim
    WebView1.LoadUrl(URL)
    Log("Loading URL: " &  WebView1.Url)
    ToastMessageShow("Loading URL: " & WebView1.Url, False)
    
    WriteSlotVal(79, URL)
End Sub

Sub btnStop_On(Index As Int, Tag As String)
    btnStart.Enabled = True
    WebView1.StopLoading
    Sleep(400)
    btnStart.Value = 0
    btnStop.Value = 0
End Sub

Sub WebView1_UserAndPasswordRequired (Host As String, Realm As String) As String()
    ToastMessageShow(Host & " require Username and Password to access: " & Realm, True)
    Log(Host & " require Username and Password to access: " & Realm)
    Return Array As String("admin", "password") ' OTA update page, we set on ESP to require a login
End Sub

Sub WebView1_OverrideUrl (Url As String) 'As Boolean
    ToastMessageShow("Override URL: " &  Url, False)
    Log("Override URL: " &  Url)
End Sub

Sub WebView1_PageFinished (Url As String)
    ToastMessageShow("PageFinished: " &  Url, False)
    Log("PageFinished: " & Url)
End Sub

My questions are:

1) I've used UserAndPasswordRequired sub to pass the username and password, after I added this It successfull login and I see the OTA update page, but want I want is to show the original login (as showed on browser) so the user insert username and password itself directly on the login view, is that possible?

2) When I load a page, pressing on button to choose a binary file, a message show that there are no applications to do it, I do not khow how I can handle it... Maybe need an Intent or I'm wrong ?

Attached some images of attemp on the app and the original login from Android FireFox browser.

Many thanks for any clarification.
 

Attachments

  • Page_loaded.jpg
    Page_loaded.jpg
    99.6 KB · Views: 238
  • No_app_found.jpg
    No_app_found.jpg
    69.3 KB · Views: 241
  • Firefox_login.jpg
    Firefox_login.jpg
    97.4 KB · Views: 268

max123

Well-Known Member
Licensed User
Longtime User
Here is my cell android version.
I have a Nexus 7 2013 too, but have the same identical Android version, 6.0.1, and cannot updated, I already have the last update from Goggle on original stock rom.
I compile my apps with API level 28
 

Attachments

  • 20220128_201023.jpg
    20220128_201023.jpg
    150.2 KB · Views: 113
Last edited:
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Okay, then the problem is somewhere else, most likely the problem is in B4A 7.8 because it's an old IDE and the library was done with the help of Eclipse and B4A11. For the weekend I will write a simple B4A example without a library. In any case, work on installing the latest B4A and the latest SDK package as you will encounter many problems with new libraries and protocols. The sooner you switch to B4A 11.2 the better for you, trust me.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
@warwound with his WebViewExtras had the similar problem with onActivityResult while uploading files, take a look here, maybe can help to know what is the problem...
https://www.b4x.com/android/forum/t...activityresult-was-released.18186/#post104464

I know that my B4A is not the last version but 7.80 is not so very old comparated to 11.2.

I don't think is this the problem, fortunately I never had problems with other libraries, I even developed various libraries on Eclipse too for B4A and B4J both not updated at latest versions without particular problems, they worked, I even wrapped some other libraries as for example Zip4j to extract/compress files without or with password, some parts of RSyntaxTextArea to create a view capable to be used as text editor, If I'm right (but not sure) is the same editor used in the B4X IDE by Erel and even the same used in Processing and Arduino IDE. So maybe some change in APIs ?

But yes, the best option is always to be updated, for now I cannot because require me to change my PC, operating system, do a lots of backups etc.... for now I have no work so I cannot change it, but it is the next step.

Maybe can be the change to Google API up 29+ ?
What API do you use to compile it ?

The good things are that because I develop on slow PCs (I have 2) one SingleCore with 1 GB or ram and another DualCore with 2GB of ram (both with Win XP 32 bit), when I try my applications (that I search to optimize to work as fast possible on my PC), on other modern PCs these applications works very very fast :p ;):D

Like to optimize a code on Arduino Uno and then use it on a fast PC 😆
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Last edited:
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Upvote 0

Ivica Golubovic

Active Member
Licensed User
This example does not use the UltimateWebView library. Just replace the URL with your IP address and give it a try.
 

Attachments

  • FileUpload.zip
    11 KB · Views: 120
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
This example does not use the UltimateWebView library. Just replace the URL with your IP address and give it a try.
Many thanks Ivica,

The IDE took me a syntax error on line 100 of main:
B4X:
If Args(0).As(Int)=-1 Then

The (int) cast is a new IDE feature ?

I suppose can just replaced with this, right ?
B4X:
    Dim tmp As Int = Args(0)
    If tmp = -1 Then
And even I replaced:
B4X:
Service.StopAutomaticForeground with Service.StopForeground
but how I can get the foreground id ?

Sorry, but I'm not pratice with Services, I never used it, all my apps uses Activities, even the one for 3D printing, and this is something I need to change to work in background, for now I had to set the Android display time to 30 minutes, after this the screen goes off and the app stop to work because in pause, the 3D print stop.

For now I just touch the screen at least every 30 minutes.

When all seem to work I will create a backup and search to move all non UI functions to Services, note that in my app I even used a servive with a timer to send every second a command to retrieve a temperature... and yes this is a bad idea because I suppose the app will exit and the service continue in background. But this is another question....
 
Last edited:
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Many thanks Ivica,

The IDE took me a syntax error on line 100 of main:
B4X:
If Args(0).As(Int)=-1 Then

The (int) cast is a new IDE feature ?

I suppose can just replaced with this, right ?
B4X:
    Dim tmp As Int = Args(0)
    If tmp = -1 Then
And even I replaced:
B4X:
Service.StopAutomaticForeground with Service.StopForeground
but how can get the id ?
Yes, you can adapt to your IDE.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Do not load the web page, I suppose it do not provide the login, I add It and Inform you.
I still search to know your code that even use inline Java.
Many thanks
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I tried your code, now that I've added a login the page open, when I press the button to select a file the button still remain around one second pressed, then I receive te same error on the log, then file not selected and Intent null. Here the log:
Logger connesso a: asus ASUS_Z00LD
--------- beginning of main
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
File Not Selected
Intent is NULL
** Activity (main) Pause, UserClosed = false **
onActivityResult: wi is null
** Activity (main) Resume **
File Not Selected
Intent is NULL
** Activity (main) Pause, UserClosed = false **
onActivityResult: wi is null
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
it seems to pass through, I had the same problem with a file manager to open gcode files to print, I do not remember now the module name, just one DoEvents solved the problem, now it wotk well I never had problems, I use it from 3 years, and works.

Maybe place one DoEvents or Sleep(0) in the right position can help?
 
Last edited:
Upvote 0

Ivica Golubovic

Active Member
Licensed User
I tried your code, now that I've added a login the page open, when I press the button to select a file the button still remain around one second pressed, then I receive te same error on the log, then file not selected and Intent null. Here the log:

it seems to pass through, I had the same problem with a file manager to open gcode files to print, I do not remember now the module name, just one DoEvents solved the problem, now it wotk well I never had problems, I use it from 3 years, and works.

Maybe place one DoEvents or Sleep(0) in the right position can help?
There is something wrong with the initial intent sent by the WEB source. Replace the sub "Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object)" with this below (copy / paste only). Send me a log printout.
Copy/Paste:
Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object)
    'Log("ShowFile_Chooser")
  
    Dim FileChooserParams1 As Reflector
    FileChooserParams1.Target=FileChooserParams
    Dim Mode As Int=FileChooserParams1.RunMethod("getMode")
    Dim FileChooserParamsIntent As Intent=FileChooserParams1.RunMethod("createIntent")
    UploadContent=FilePathCallback
    Log(FileChooserParamsIntent)
    Log(FilePathCallback)
    Log(Mode)
  
    If Mode=1 Then
        FileChooserParamsIntent=ActivityClass.RunMethod("alowMultipleFiles",Array(FileChooserParamsIntent))
    End If
  
    If FileChooserParamsIntent.IsInitialized Then
        StartActivityForResult(FileChooserParamsIntent)
    Else
        Log("Initial intent does not exist")
    End If
End Sub
 
Last edited:
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Have also a look at this thread.


You can just do it by adding a sending of an mqtt message for update from OTA.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
There is something wrong with the initial intent sent by the WEB source. Replace the sub "Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object)" with this below (copy / paste only). Send me a log printout.
Copy/Paste:
Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object)
    'Log("ShowFile_Chooser")
 
    Dim FileChooserParams1 As Reflector
    FileChooserParams1.Target=FileChooserParams
    Dim Mode As Int=FileChooserParams1.RunMethod("getMode")
    Dim FileChooserParamsIntent As Intent=FileChooserParams1.RunMethod("createIntent")
    UploadContent=FilePathCallback
    Log(FileChooserParamsIntent)
    Log(FilePathCallback)
    Log(Mode)
 
    If Mode=1 Then
        FileChooserParamsIntent=ActivityClass.RunMethod("alowMultipleFiles",Array(FileChooserParamsIntent))
    End If
 
    If FileChooserParamsIntent.IsInitialized Then
        StartActivityForResult(FileChooserParamsIntent)
    Else
        Log("Initial intent does not exist")
    End If
End Sub
Sorry, I've read you only now,

This night I had success with a bit modified version of Erel's exampe with a very small code, I will test your suggestions, many thanks, but my conclusions at this point are the same as your, something is wrong while create the intent in the ShowFileChooser sub, you and Erel used a bit different approach, you use a reflection, Erel uses a ContentChooser object, so here both ShowFileChooser Subs comparated:
Your code:
Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object) 'Ignore
    Log("ShowFile_Chooser")
 
    Dim FileChooserParams1 As Reflector
    FileChooserParams1.Target = FileChooserParams
    Dim Mode As Int = FileChooserParams1.RunMethod("getMode")
    Dim FileChooserParamsIntent As Intent = FileChooserParams1.RunMethod("createIntent")
    UploadContent = FilePathCallback
 
    Log("Mode: " & Mode)   'DEBUG
 
    If Mode = 1 Then
        FileChooserParamsIntent = ActivityClass.RunMethod("alowMultipleFiles", Array(FileChooserParamsIntent))
    End If
 
    If FileChooserParamsIntent <> Null Then
        Log("Initial intent exist, call StartActivityForResult with the Intent")
        StartActivityForResult(FileChooserParamsIntent)
    Else
        Log("Initial intent does not exist")
    End If
End Sub
Erel's code:
Private cc As ContentChooser ' Should be in Process_Globals
Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object) 'Ignore
    Log("ShowFile_Chooser")
 
    cc.Initialize("CC")

'    cc.Show("*/*", "Choose File") ' MIME for all files    Original
'    cc.Show("application/octet-stream", "Choose Binary File")
    cc.Show("application/octet-stream/*", "Choose Binary File")  ' Bynary files
 
    Wait For CC_Result (Success As Boolean, Dir As String, FileName As String)
    Dim jo As JavaObject = Me
    If Success Then
        Log("ContentChooser file name: " & FileName)
        File.Copy(Dir, FileName, Starter.Provider.SharedFolder, "TempFile")
        jo.RunMethod("SendResult", Array(Starter.Provider.GetFileUri("TempFile"), FilePathCallback))
    Else
        jo.RunMethod("SendResult", Array(Null, FilePathCallback))
    End If
End Sub

Even in the Java code you use this to raise the event:
Java:
processBA.raiseEvent(this, "showfilechooser", filePathCallback, fileChooserParams);  // From Ivica's code
and Erel used this instead:
B4X:
processBA.raiseEventFromUI(this, "showfilechooser", filePathCallback, fileChooserParams)  // From Erel's code
I do not think is this the probem because tried both and both works

Your code is different because it can handle multiple files, this absolutely no needed on this my project, but it is very good to use on other projects where need to upload multiple files at once. So now I want to know your code difference vs Erel's code.

I've attached both zip files of a bit modified your last UploadFile (only B4A code, no UltimateWebView) and a bit modified Erel's example, just I've added login.

With your code always I have the same error, Intent return null pointer, the Erel's code works well and I can do OTA update without 100kb limitation, I think this is only a B4X server side that limit it, so users to test the code just upload small files.
Log images for both codes is attached too.

Because the OTA process is a bit longer task, about 40 seconds / one minute, and the browser after press the Update button do not show any progress and seem urresponsive (but it still work well in background) I want to search a way to show an progressbar, maybe using javascript to read the value ?
On the ArduinoOTA C++ class there is a progress, but it only show in the Arduino IDE Serial log, not in the web page, the web page only show "Success! Rebooting... if OTA succesfully updated or an error message otherwise, in this case ESP reboots and continue to use the original firmware.

Question:
1) You think this is possible?

I've other 2 questions, I am your torture today 😂

2) In Erel's code the file name showed on the webview after file is selected always is TempFile as for this line...
B4X:
File.Copy(Dir, FileName, Starter.Provider.SharedFolder, "TempFile")
I've tried to change it with right file name of selected file, but the ContentChooser.FileName return it as:
ContentChooser file name: content://com.android.externalstorage.documents/document/primary%3AMaxCNC%2FOTA%2FMaxCNC-Server-1.0.3-FTDI.ino.d32_pro.bin
So I need to use String.substring or there is a better and elegant way to extract the real file name to show in the web page?

3) Erel's code use JavaObject to set WebChromeClient with an instance of current B4A Package Name, can this be archived directly in the Java code ?

Many thanks for your great support
Max
 

Attachments

  • FILE_UPLOAD_FROM_WEBVIEW.zip
    11.9 KB · Views: 113
  • FileUpload3.zip
    10.1 KB · Views: 122
  • ErelLog.PNG
    ErelLog.PNG
    42.5 KB · Views: 119
  • IvicaLog.PNG
    IvicaLog.PNG
    30.3 KB · Views: 117
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I've tried your new ShowFileChooser sub but nothing change, always the same error, note that I've added some log debugs.
Attached the log image.

Tks for MQTT tip, but I don't like the idea to complicate somethig already working with a small code and some JavaObject and inline Java code.

Now the next step for me is to try replace your reflection code and use one ContentChoser object to see if and the file manager appear so the Intent do not return null pointer to see if this is working with your code.

I will inform you if I've success.

Many thanks
 

Attachments

  • Log.PNG
    Log.PNG
    43.8 KB · Views: 111
Last edited:
Upvote 0

Ivica Golubovic

Active Member
Licensed User
Even in the Java code you use this to raise the event:
Java:
processBA.raiseEvent(this, "showfilechooser", filePathCallback, fileChooserParams); // From Ivica's code
and Erel used this instead:
B4X:
processBA.raiseEventFromUI(this, "showfilechooser", filePathCallback, fileChooserParams) // From Erel's code
I do not think is this the probem because tried both and both works
The essence is the same for both methods, the difference in this case has no effect.
processBA.raiseEventFromUI is "void" and can not accept return value. I preffer to use processBA.raiseEvent because you can return result as Object to java code if is needed.

My example is for uploading files of various types defined by Web Source via Intent. With Content Chooser you have to define uploadable file types or allow all file types (* / *).

The problem in my example and in your case is that WebSource Intent does not use the correct MimeType for file types. You can easily fix this by entering the following lines to ShowFileChooser Sub:
Example::
Private Sub ShowFileChooser (FilePathCallback As Object, FileChooserParams As Object) 'Ignore
    Log("ShowFile_Chooser")
  
    Dim FileChooserParams1 As Reflector
    FileChooserParams1.Target = FileChooserParams
    Dim Mode As Int = FileChooserParams1.RunMethod("getMode")
    Dim FileChooserParamsIntent As Intent = FileChooserParams1.RunMethod("createIntent")
   
    'This part of code will repair Intent
    Dim IntentJO As JavaObject=FileChooserParamsIntent
    Dim IntentType As String=IntentJO.RunMethod("getType",Null)
    If IntentType.Contains(".bin") Then
        FileChooserParamsIntent.SetType("application/octet-stream/*")
    End If
    '-----------------------------
  
    UploadContent = FilePathCallback
    If Mode = 1 Then
        FileChooserParamsIntent = ActivityClass.RunMethod("alowMultipleFiles", Array(FileChooserParamsIntent))
    End If
  
    If FileChooserParamsIntent <> Null Then
        Log("Initial intent exist, call StartActivityForResult with the Intent")
        StartActivityForResult(FileChooserParamsIntent)
    Else
        Log("Initial intent does not exist")
    End If
End Sub
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
The essence is the same for both methods, the difference in this case has no effect.
processBA.raiseEventFromUI is "void" and can not accept return value. I preffer to use processBA.raiseEvent because you can return result as Object to java code if is needed.
For this I just intend the difference from RaiseEvent and RaiseEventUI.

The problem in my example and in your case is that WebSource Intent does not use the correct MimeType for file types. You can easily fix this by entering the following lines to ShowFileChooser Sub:
I will try it and post the feedback.

Many Thanks.
 
Upvote 0
Top