This is an example of how we can use B4AServer to manage the deployment and updates of multiple Android applications on multiple devices.
It works in the following way:
- The device application wants to check for updates.
- It connects to the desktop server and downloads a CSV file that lists the current applications and their versions.
- The device checks the version and existence of each of the applications and downloads and installs the required applications.
The desktop 'files' folder should contain the APK files and the CSV file:
The content of the csv file is:
As you can see each row has three fields: package name, apk file and the version.
The difficult part in the code is to manage the installation intents. It is not possible to send all of the intents together. So it is sending them one by one.
To build this project you should add B4AServer and B4AServerService modules which are available here: http://www.b4x.com/forum/additional-libraries-official-updates/9679-b4aserver-files.html
The following libraries are required: HTTP, Network, RandromAccessFile, Phone (for the version check and intents) and StringUtils (for the CSV parsing).
The main Activity code:
It works in the following way:
- The device application wants to check for updates.
- It connects to the desktop server and downloads a CSV file that lists the current applications and their versions.
- The device checks the version and existence of each of the applications and downloads and installs the required applications.
The desktop 'files' folder should contain the APK files and the CSV file:
The content of the csv file is:
B4X:
anywheresoftware.b4a.samples.json,JSON.apk,1
anywheresoftware.b4a.samples.linkedlist,LinkedList.apk,2
anywheresoftware.b4a.charts,Charts.apk,1
anywheresoftware.b4a.samples.animation,Animation.apk,2
The difficult part in the code is to manage the installation intents. It is not possible to send all of the intents together. So it is sending them one by one.
To build this project you should add B4AServer and B4AServerService modules which are available here: http://www.b4x.com/forum/additional-libraries-official-updates/9679-b4aserver-files.html
The following libraries are required: HTTP, Network, RandromAccessFile, Phone (for the version check and intents) and StringUtils (for the CSV parsing).
The main Activity code:
B4X:
'Activity module
Sub Process_Globals
Dim ServerName As String
ServerName = "test1" '*********** Change to your server value
Dim checkForUpdatesTask As Int
Dim UpdateTable As List
Dim DownloadApkTask As Int
Dim DuringResume As Boolean
Dim InstallationInProgress As Boolean
Dim LastIntent As Intent
Dim tmrResendIntent As Timer
End Sub
Sub Globals
Dim btnCheckUpdates As Button
End Sub
Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then
B4AServer.Initialize("http://66.84.14.57/android/b4a_server.php", ServerName, "Main")
UpdateTable.Initialize
tmrResendIntent.Initialize("tmrResendIntent", 500)
End If
btnCheckUpdates.Initialize("btnCheckUpdates")
btnCheckUpdates.Text = "Check for updates"
Activity.AddView(btnCheckUpdates, 10dip, 10dip, 300dip, 100dip)
End Sub
Sub Activity_Resume
tmrResendIntent.Enabled = False
DuringResume = True
'Raise events for tasks that completed while our activity was paused
For i = 0 To B4AServer.TasksFinishedWhilePaused.Size - 1
Dim Result As TaskResult
Result = B4AServer.TasksFinishedWhilePaused.Get(i)
Log("From resume: " & Result)
TaskComplete(Result)
Next
B4AServer.TasksFinishedWhilePaused.Clear
'Activity_Resume will be called after each installation
'So we process the next package here (if such is available).
ProcessNextRow
DuringResume = False
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub btnCheckUpdates_Click
checkForUpdatesTask = B4AServer.ReceiveFile("files.csv")
btnCheckUpdates.Enabled = False
InstallationInProgress = True
End Sub
Sub TaskComplete(Result As TaskResult)
Log("Task=" & Result.Id & " completed. Success=" & Result.Success & ", Message=" & Result.Message)
If Result.Success Then
Select Result.Id
Case checkForUpdatesTask
HandleFilesTable(Result.Id) 'The task id is the file name.
Case DownloadApkTask
InstallPackage(Result.Id)
End Select
Else
Msgbox(Result.Message, "Error occurred")
btnCheckUpdates.Enabled = True
InstallationInProgress = False
End If
End Sub
Sub HandleFilesTable(FileName As String)
Dim su As StringUtils
UpdateTable = su.LoadCSV(B4AServer.DownloadFilesFolder, FileName, ",")
'The next line will process the first row (which will lead to processing all rows).
'If however the Activity was paused during the call to "check updates" call then
'we do not want to ProcessNextRow as it will happen anyway in Sub Activity_Resume.
If DuringResume = False Then ProcessNextRow
End Sub
Sub ProcessNextRow
Dim pm As PackageManager
Dim row() As String
'Each row includes the following fields: package name, apk name, version code
For i = UpdateTable.Size - 1 To 0 Step -1
row = UpdateTable.Get(i)
UpdateTable.RemoveAt(i)
'Check if we need to install this package.
If ShouldInstallPackage(row(0), row(2)) Then
DownloadApkTask = B4AServer.ReceiveFile(row(1)) 'request the apk.
Log("Requesting " & row(1) & ", task=" & DownloadApkTask)
Return
Else
Log("no need to install: " & row(0))
End If
Next
If InstallationInProgress Then
ToastMessageShow("Finished updating applications.", True)
btnCheckUpdates.Enabled = True
InstallationInProgress = False
End If
End Sub
Sub ShouldInstallPackage(Package As String, NewVersion As Int) As Boolean
Try
Dim version As Int
Dim pm As PackageManager
version = pm.GetVersionCode(Package)
Return version < NewVersion
Catch
'An exception will be thrown if the package do not exist. In this case we need to install.
Return True
End Try
End Sub
Sub InstallPackage (FileName As String)
Dim i As Intent
i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(B4AServer.DownloadFilesFolder, FileName))
i.SetType("application/vnd.android.package-archive")
StartActivity(i)
'in some cases at least in the emulator the Intent is ignored.
'we use this timer to resend the intent. If the installation has
'already started then this activity will paused and the timer will not tick.
LastIntent = i
tmrResendIntent.Enabled = True
End Sub
Sub tmrResendIntent_Tick
Log("Resending intent")
StartActivity(LastIntent)
End Sub