Android Code Snippet Check an update server, fetch and install a new app version

For various reasons, I have a few apps that aren't distributed via stores. To make life a little easier, I've set up a script on one of my servers that can be queried by an app, to find out the most up to date version, display info about it. This is not the most elegant B4A code - it could use resumable subs now - but it does the job of checking for updates, and then if required, downloading and prompting the user to install.

The script at api.nigelwhitfield.net/appinfo is written in PHP, but could be in anything; it just looks up info in the database and returns a JSON string, the format of which is fairly obvious from the B4A code.
appinfo is an integer that represents the build number of the app and used for comparison, rather than the more user-friendly version number (eg 246, vs 2.4.6). It's a pretty trivial script, but if anyone wants to see the code, I'm happy to share it. The same server provides info for my desktop apps, too. So once I have new versions to deploy, I just upload them to the server, and update the info in the database. Users can either check manually via a menu option, or in some apps, it happens automatically based on time since last check.

B4X:
Sub updateCheck_click
   ' check with the app info service for update information
   Dim appid As Int = 2
   Dim infourl As String = "https://api.nigelwhitfield.net/appinfo/"
 
   Dim check As HttpJob
 
   check.Initialize("appinfo",Me)
   check.PostString(infourl,"platform=android&appcode=" & appid)
End Sub

Sub jobDone( job As HttpJob )
If job.Success Then
   If job.JobName = "appinfo" Then
     ' getting the info aboutan app
 
     Dim apiJSON As JSONParser
     Dim apiresults As Map
     apiJSON.Initialize(job.GetString)
 
     apiresults = apiJSON.NextObject
     If ( apiresults.Get("status") = "error" ) Then
       Msgbox("Invalid response received from update server","Sorry, there was an error")
     Else
       Dim appdetails As Map = apiresults.Get("appinfo")
       If appdetails.Get("latestbuild") > appinfo Then
         Dim newinfo As String
         newinfo = "Version " & appdetails.get("latestversion") & " (build " & appdetails.Get("latestbuild") & ")" & CRLF & CRLF & appdetails.Get("notes")
         Dim choice As Int
         choice = Msgbox2(newinfo,"Update available","Install","","Ignore",Null)
         If choice = DialogResponse.POSITIVE Then
           newbuild = appdetails.Get("latestbuild")
           Dim downloader As HttpJob
           downloader.Initialize("update",Me)
           downloader.Download(appdetails.get("url"))
         End If
       Else
         Msgbox("Your app is up to date","No update available")
       End If
     End If
   Else
     ' must be a download and install request
     Dim apkFile As OutputStream
     apkFile = File.OpenOutput(File.DirDefaultExternal,"estim4android-" & newbuild & ".apk",False)
     File.Copy2(job.GetInputStream,apkFile)
     apkFile.Close
 
     Dim i As Intent
     i.Initialize(i.ACTION_VIEW,"file://" & File.Combine(File.DirDefaultExternal,"estim4android-" & newbuild & ".apk"))
     i.SetType("application/vnd.android.package-archive")
     StartActivity(i)
   End If
 Else
   Msgbox("Sorry. Please try later","Unable to contact server")
 End If
 
End Sub
 

nwhitfield

Active Member
Licensed User
Longtime User
Here's what it looks like in-app
newersion.png
 

DonManfred

Expert
Licensed User
Longtime User
Dim i As Intent
i.Initialize(i.ACTION_VIEW,"file://" & File.Combine(File.DirDefaultExternal,"estim4android-" & newbuild & ".apk"))
i.SetType(
"application/vnd.android.package-archive")
StartActivity(i)
Only works up to Android 6 (i think).
Starting from Android 7 you need to use a Fileprovider to install the APK after download.
 

udg

Expert
Licensed User
Longtime User
If I understand it correctly, you "replaced" the need for a library like AppUpdating with an on-demand service.
Just query the service and donwload an update if available (and user wants to).
Would you like to share the PHP code and DB structure too? Thanks.
 

nwhitfield

Active Member
Licensed User
Longtime User
Yes, that's essentially it. This is the SQL to set up the apps table. I use the 'arm' platform here to distinguish versions of some of my XoJo apps that are built for Linux X86 and Linux ARM. latestversion is a 'display friendly' name, like 2.4.2, while the build is an integer, like 242 (or however you want to number them)

B4X:
CREATE TABLE `apps` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `appname` char(100) DEFAULT NULL,
  `appcode` int(11) DEFAULT NULL,
  `platform` enum('win','mac','ios','android','linux','web','arm') DEFAULT NULL,
  `lastupdate` date DEFAULT NULL,
  `latestversion` char(10) DEFAULT NULL,
  `latestbuild` int(11) DEFAULT NULL,
  `url` char(200) DEFAULT NULL,
  `notes` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

nwhitfield

Active Member
Licensed User
Longtime User
And this is the PHP script (obviously, amend database connection details appropriately)

B4X:
<?php

// api.nigelwhitfield.net info service
// returns status of an app and location to download
//

// Version 1.0
// Date: 2017-07-22

$appdb = new mysqli('localhost','someUserName','somePassword','databaseContainingAppsTable') ;
$appdb->query('set names utf8') ;

$status = 'error' ;

if ( isset($_REQUEST['platform']) &&isset($_REQUEST['appcode'])) {
   // see if we can find a record in the database
   $appq = $appdb->stmt_init() ;
   if ( $appq->prepare("SELECT appname, platform, lastupdate, latestversion, latestbuild, url, notes FROM apps WHERE appcode = ? AND platform = ?") ) {
     $appq->bind_param('is',$_REQUEST['appcode'],$_REQUEST['platform']) ;
     $appq->execute() ;
     
     $appq->store_result() ;
     if ( $appq->num_rows == 1 ) {
       $appq->bind_result($appname,$platform,$lastupdate,$latestversion,$latestbuild,$url,$notes) ;
       $appq->fetch() ;
       
       $result = array( 'appname' => $appname,
                'platform' => $platform,
                'lastupdate' => $lastupdate,
                'latestversion' => $latestversion,
                'latestbuild' => $latestbuild,
                'url' => $url,
                'notes' => $notes ) ;
       $status = 'ok' ;
     }
   }
     
}

$results['status'] = $status ;
if ( $status == 'ok' ) {
   $results['appinfo'] = $result ;
}

header('Content-type: application/json') ;

print(json_encode($results)) ;
?>
 
Top