Android Question How to automate app updating?

udg

Expert
Licensed User
Longtime User
Note: posts from #1 to #8 refer to an old version of the library based on an Activity object. Please start reading from post #9 to follow ongoing work on current version of AppUpdating.

Hi all,

I nearly completed my first "useful" app so I'm faced with the problem of how to automatically update it when new releases will be ready.
I'm not going to use any official market, just a dir on my Drupal website.

What I did so far, was to add a simple text file named after the app (in my case tmb.apk and tmb.txt) in that same dir and have its first (and only) row like this one: ver=1.02
Then I developed 3 simple functions GetCurVN, GetWebVN and UpdateApk to simply read the Version Number buried in the currently executing app (ATTRIBUTE #VersionName), the one stored on the web text file and finally download and install the new app version (if the case).

Since both GetWebVN and UpdateApk rely on HttUtils2.Download mechanism I am not able to wait for the completion of the first call before checking version and eventually call the updating sub.

How do you accomplish you apps' updating?

TIA

Umberto
 
Last edited:

udg

Expert
Licensed User
Longtime User
SOLVED?

Reading a post from Erel in another thread I modified my JobDone sub this way:

B4X:
Sub JobDone (Job As HttpJob)
    Log("--------JobDone -- JobName = " & Job.JobName & ", Success = " & Job.Success)
    If Job.Success = True Then
      Select Job.JobName
         Case "Job3"
            webver=Job.GetString.SubString(4) 'the only row is formatted as ver=1.12
             If curver < webver Then
                Log("try downloading of new version")
                UpdateApk
             End If
         Case "Jobapk"
             'copy from external to storage card
             Dim out As OutputStream
             out = File.OpenOutput(File.DirDefaultExternal,"temp.apk",False )
             File.Copy2(Job.GetInputStream, out)
             out.Close
             'intent to install new version
              Dim i As Intent
               i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(File.DirDefaultExternal, "temp.apk"))
               i.SetType("application/vnd.android.package-archive")
              StartActivity(i)
      End Select
    Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
    End If
    Job.Release
End Sub

This way, when job3 ends and has handy the webver version number, it can call the UdateApk sub which in turn activates the last (optional, base on the test done in job3) job.
I'm not sure this is the proper way to "serialize" my actions but it worked as expected.

If this is the way to go at all, what I should do to encapsulate all that behaviour in a reusable object (code, class, library..whatever) to become a standard part of my future development?

Umberto
 
Upvote 0

qsrtech

Active Member
Licensed User
Longtime User
It would be nice to see a reusable class/library to auto update.
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi qsrtech,

me too would like to simply download a library (or whatever) able to update any app stored on a website.
In the neanwhile I somehow managed to transform my code in a Library and it seems to work ("seems" it's the keyword here.. eh eh).
I am very new to B4A (and the Basic language too) so please don't rely on my work for any serious programming.

That said, here is my first library: AppUpdating!

Currently I initialize and call it this way:

B4X:
Sub Activity_Create(FirstTime As Boolean)
....
Activity.LoadLayout("Main")
If FirstTime Then CheckVersion
.....
End Sub

Sub CheckVersion
   AppUpdating.ProjectName = "eu.dgconsulting.tmb"
   AppUpdating.NewVerTxt = "http://www.dgconsulting.eu/sites/default/files/apk/tmb.txt"
   AppUpdating.NewVerApk = "http://www.dgconsulting.eu/sites/default/files/apk/TMB.apk"
   AppUpdating.LibLayout = "Main"
   ToastMessageShow("Looking for an updated version..", True)
   CallSubDelayed(AppUpdating,"LookForNewVersion")
End Sub

AppUpdating.ProjectName - you app's project name (taken from menu "Project/Package name")
AppUpdating.NewVerTxt - complete path to the txt file whose first and only row is: ver=x.xx with x.xx matching the version published on the site
AppUpdating.NewVerApk - complete path to your app's new version
AppUpdating.LibLayout - reference to one of your app's layout

In the example code above I intentionally left my real data so to make it clearer how I used the whole thing with files stored on a Drupal-based site.

Still hoping for a nice, professional tool from any expert here in the NG..

Umberto
 

Attachments

  • AppUpdating_085.zip
    9.1 KB · Views: 668
Last edited:
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi Jake,

I experimented a bit more with tha library and found it could be better if the layout passed to it would be something different from "Main".
This because the library closes its layout when finished, so if using Main for both app and library you end up with a strange effect where the screen seems to close just to reveal a second copy of itself (the one initialized for the main module).
I took the opportunity to generate a layout specific for the operations going on in the lib and modeled it after a classic "splash screen", so to show my app's logo (..copyright, credits, whatever..) and a label specifying the searching for an update.

So, now my code looks like:

B4X:
Sub Activity_Create(FirstTime AsBoolean)
....
If FirstTime Then CheckVersion
Activity.LoadLayout("Main")
.....
End Sub

Sub CheckVersion
   AppUpdating.ProjectName = "eu.dgconsulting.tmb"
   AppUpdating.NewVerTxt = "http://www.dgconsulting.eu/sites/default/files/apk/tmb.txt"
   AppUpdating.NewVerApk = "http://www.dgconsulting.eu/sites/default/files/apk/TMB.apk"
   AppUpdating.LibLayout = "lytSplash"
  'remove? ToastMessageShow("Looking for an updated version..", True)
   CallSubDelayed(AppUpdating,"LookForNewVersion")
End Sub

BTW, I update the file in the previous message so to reflect the exact version of the library.

Umberto
 
Upvote 0

androb

Member
Licensed User
Longtime User
Hello

Thank you for sharing the code. I tried using the library but I am having some problems.
When I run the app using the sample code you posted I get this error:
java.lang.NumberFormatException: Invalid double: """"
Continue?


I have changed the paths to my webserver and can access the file directly. Please can you advise what format it is expecting the version number to be in? I tried the following:

1
1.2
1.22

Each time saving the file with a single line with that version. At one point it said an index was out of bounds, but I am not sure I can reproduce that error.


I would like this function to work. I have written my own auto update with http utils, and I can download, run the intent, but the installer just dissapears. I would like it to restart the application after installing the update. Is this possible? I have found one thread about it, but the answer is vague and I cannot work out how to get it to work (http://www.b4x.com/android/forum/threads/programmatically-restarting-an-app.27544/#post-175034)
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi Androb,

sorry to hear about the difficulties you incurred in.
Here it is my app's main module settings:

B4X:
#Region Module Attributes
   #FullScreen: False
   #IncludeTitle: True
   #ApplicationLabel: Take me back
   #VersionCode: 1
   #VersionName: 1.14
   #SupportedOrientations: unspecified
   #CanInstallToExternalStorage: False
#End Region

What I do is simply to update the value under #VersionName each time I have a new version to publish and, of course, update the row in the text file accompanying it.
The library logic is:
1. read the current #VersionNumber
2. read the single row in text file and extract from 4th char to the end as the possibly new Version Number (this is because I've a row like ver=x.xx)
3. compare those values and if currentver < textfilever then use httputil2.download to download app's new version and call the installation intent

I too would like to have the app run again after installation and soon will try some experimenting about that (thanks for the link!)

As said in post #4 I'm very new to B4A and just discovered how to build up classes. This means I'm going to re-make AppUpdating basing my work on classes instead of an activity like currently it is.
What I would like to finish with is a library that publish a few "commands" useful to check for a new version but also to display a splash screen and some status variables in order to report back to the Main calling it what happened inside.
If you have any suggestions let me know.

All the above will find it's natural place in the Libraries section of this great NG. When ready I will edit the #1 post in this thread to announce it.
In the meanwhile if I can be of any further help with the library as-is just ask.

Umberto
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Note: since AppUpdating is still in its infancy and I don't feel it's ready to migrate to the contribued libraries section of the forum, I'll keep publish here newer versions of it, keeping at the same time older ones because of inconsistencies between versions.
Sorry for any inconvenience.


Hi all,

when they say B4A is a RAD definitely they underestimate its power!
Reading only a few threads and looking at a single example code I could retool my AppUpdating lib using classes, adding a splash screen and even a call back function. Can't believe it took less than a day! I'm really impressed.

So, please, find attached version 1.02 of AppUpdating. It is still a work in progress so please don't rely on it for production code. Feel free to suggest improvements, hints and obviously let me know about errors (or should i say horrors? eh eh).

That said, since version 1.02 is so much different from its previous attempt, I believe you may find it useful if I publish my actual code for calling and managing the lib. Here it is:

B4X:
Sub Globals
..
  Dim apkupdt As AppUpdating
End Sub

Sub Activity_Create(FirstTime As Boolean)
   ...
   Activity.LoadLayout("Main")
   ...
   If FirstTime Then
     apkupdt.Initialize(Me,"testlib")
     apkupdt.PackageName = "eu.dgconsulting.tmb"
     apkupdt.NewVerTxt = "http://www.dgconsulting.eu/sites/default/files/apk/tmb.txt"
     apkupdt.NewVerApk = "http://www.dgconsulting.eu/sites/default/files/apk/TMB.apk"
     apkupdt.SetAndStartSplashScreen(Activity,LoadBitmap(File.DirAssets, "tmb0.png"))  'this one is optional
     apkupdt.LookForNewVersion
  End If 
End Sub

Sub testlib_StopSplashScreen
   If apkupdt.IsDone Then
     Log("A new version is available: " & apkupdt.NewVerAvailable)
     Log("Asked user to update apk: " & apkupdt.AppUpdated)
     apkupdt.StopSplashScreen
  End If
End Sub

If you decide to use a splash screen just note that it gets superimposed on your main layout (it's made up of a panel and the bitmap you pass as the second parameter on function SetAndStartSplashScreen). In the call back function testlib_StopSplashScreen (I've to decide for a better name..) than you simply call apkupdt.StopSplashScreen and the splash screen is removed.
Otherwise simply comment out both SetAndStartSplashScreen and apkupdt.StopSplashScreen.

Property apkupdt.NewVerAvailable simply tells you an upgrade exists for you apk
Property apkupdt.AppUpdated, when True means the newer apk was downloaded and the intent for its installation was called (but we don't know if the user applied the change).

There's a lot more work to be done before I dare to publish this lib in the contributed libraries forum, but now I feel I'm on the right track..

Umberto
 

Attachments

  • AppUpdating_102.zip
    5.5 KB · Views: 472
  • AppUpdating_105.zip
    6 KB · Views: 572
Last edited:
Upvote 0

qsrtech

Active Member
Licensed User
Longtime User
UDG, if we really wanna get fancy you can set up your auto update to have your app subscribe to a "push" service and when you update it you can send pushes to all registered devices and and then the app can pull the new version and update it.
 
Upvote 0

qsrtech

Active Member
Licensed User
Longtime User
It's sort of like google play. they probably send pushes as well. One prob will google play is it can take quite a while for a new version to propagate and notify users of an update and you actually have to publish there. Also, they have to have it set to "Auto Update". With doing it "internally", you update your APK on a server, and rather than all the devices poll and check a "version" text file, you send "pushes" when you update the APK. Probably use a DB to maintain the subscribers and run a script to handle the "pushes". I recently created a COM DLL that can send pushes from SQL Server, or pretty much any other COM environment. Could also use an ASP page to send the pushes, either with my DLL or possibly with ASP functions on their own.
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi all,

please find in post #9 above version 1.05 of lib AppUpdating.
I introduced two new properties (UserName and UserPassword) needed to access a password protected folder on the server holding newer versions of your app.
Also new is function GetCurVN that simply returns as a string the content of Attribute #VersionName.
Property WebVN contains the value read from the text file on the server; is valid only in the callback function (since you have to call LookforNewVersion to assign a value to it) or after a call to ReadWebVN (another last minute addition.. eh eh).

Umberto
 
Last edited:
Upvote 0

udg

Expert
Licensed User
Longtime User
#Jack, you're too kind.
#merlin, didn't try yet anything different from free-access and password-protected folders on shared hosted website
#qsrtech, wow! I'm not sure I could handle all that.. Anyway, maybe Erel or any volunteer here could set up a simplified market for our apps, basing its functioning on what you outlined. It could even be a paid service (I mean, for an annual fee I "buy" a page where to upload my apps and their upgrades while an automatic push service sends messages to the installed base of those same apps, better if using a db to restrict that to the intended recipients). This way, we have only to develop the receiving part of the push service (if it's not already done for some other project in the forum).
BTW, have ever read this thread?

My next steps would go in the direction of consolidating the code, introducing some error handling and simplify the status managing (too many properties now).

Umberto
 
Last edited:
Upvote 0

qsrtech

Active Member
Licensed User
Longtime User
#qsrtech, wow! I'm not sure I could handle all that.. Anyway, maybe Erel or any volunteer here could set up a simplified market for our apps, basing its functioning on what you outlined. It could even be a paid service (I mean, for an annual fee I "buy" a page where to upload my apps and their upgrades while an automatic push service sends messages to the installed base of those same apps, better if using a db to restrict that to the intended recipients). This way, we have only to develop the receiving part of the push service (if it's not already done for some other project in the forum).
BTW, have ever read this thread?

My next steps would go in the direction of consolidating the code, introducing some error handling and simplify the status managing (too many properties now).

Umberto

Thanks for the push link. Also, haven't tried your library yet but does it silently updated the app or do you still need the user to accept it, etc?
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Hi,

from what I read so far it's an Android spec that wants the user to choose whether to install or not any app (or update), so no silent install should be possible.
What it would be very nice is if it were possible to automatically relaunch the app (its newer version) once the user accepted the install.
At the moment we have:
0. launch the app
1. discovery of newer version
2. download of newver version
3. prompt the user for installation

I hope in the future to be alble to add:
4. once installed newer version, reload the app

Umberto
 
Upvote 0
Top