diff --git a/Lanterna2.b4a.meta b/Lanterna2.b4a.meta index 538816a..c2dbca7 100644 --- a/Lanterna2.b4a.meta +++ b/Lanterna2.b4a.meta @@ -28,6 +28,6 @@ ModuleClosedNodes6= ModuleClosedNodes7= ModuleClosedNodes8= ModuleClosedNodes9= -NavigationStack=Principal,Activity_Create,211,6,Principal,b_mesaCerrar_Click,1340,0,Main,Process_Globals,30,0,appUpdater,Process_Globals,78,6,Principal,b_pagoCerrar_Click,1464,5,Principal,p_resItem_LongClick,3881,6,Principal,b_resumen_Click,3734,3,Principal,b_cambioPagos_Click,3900,3,Visual Designer,principal.bal,-100,6,Principal,llenaHistorial,1014,0 +NavigationStack=Principal,p_resItem_LongClick,3881,6,Principal,b_resumen_Click,3734,3,Principal,b_cambioPagos_Click,3900,3,Visual Designer,principal.bal,-100,6,Principal,llenaHistorial,1014,0,numeroATexto,Class_Globals,18,0,numeroATexto,Initialize,21,0,updateAvailable,Process_Globals,0,0,updateAvailable,Activity_Resume,43,0,appUpdater,Process_Globals,80,1 SelectedBuild=0 -VisibleModules=7,6,8 +VisibleModules=7,6,8,5,9,1 diff --git a/appUpdater.bas b/appUpdater.bas new file mode 100644 index 0000000..f7a6133 --- /dev/null +++ b/appUpdater.bas @@ -0,0 +1,292 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Service +Version=10.2 +@EndOfDesignText@ +#Region Service Attributes + #StartAtBoot: False +#End Region + +'//////////////////////////////////////////////////////////////////////////////////////////// +'//// Servicio para revisar si hay actualizacion de aplicación, usa la +'//// actividad "updateAvailable" para mostrar mensajes. +'//// +'//// https://www.b4x.com/android/forum/threads/update-your-app-without-using-the-gplaystore.109720/#content +'//// +'//// En la actividad del la cual se va a llamar la revision de actualizacion +'//// hay que agregar los siguientes Subs: +'//// +' Sub boton_que_llama_revision_Click +' StartService(appUpdater) +' End Sub +' +' appUpdater - Mostramos el anuncio de que se esta descargando el nuevo apk +' Sub muestraProgreso +' ProgressDialogShow("Descargando actualización") +' End Sub +' +' appUpdater - Ocultamos el anuncio de que se esta descargando el nuevo apk +' Sub ocultaProgreso +' ProgressDialogHide +' End Sub +'//// +'//// Requiere las siguientes librerias: +'//// +'//// * JavaObject +'//// * OkHttpUtils2 +'//// * Phone +'//// * RuntimePermissions +'//// * appUpdating +'//// +'//// Requiere las siguientes lineas en el manifiesto: +'//// +' AddManifestText( +' ) +' AddApplicationText( +' +' +' +' ) +' CreateResource(xml, provider_paths, +' +' +' +' +' +' ) +' AddPermission(android.permission.REQUEST_INSTALL_PACKAGES) +' AddPermission(android.permission.INTERNET) +' AddPermission(android.permission.INSTALL_PACKAGES) +' AddPermission(android.permission.READ_EXTERNAL_STORAGE) +' AddPermission(android.permission.WRITE_EXTERNAL_STORAGE) +' AddPermission(android.permission.READ_PHONE_STATE) +' AddPermission(android.permission.WAKE_LOCK) +'//// +'//////////////////////////////////////////////////////////////////////////////////////////// + +Sub Process_Globals + 'These global variables will be declared once when the application starts. + 'These variables can be accessed from all modules. + + 'Aqui va la liga al archivo .ver en el servidor que contiene la información de la aplicacion + Public lnk As String = "https://keymon.lat/movil/Lanterna/Lanterna.ver" + '##################################################### + '################# RUTA EN EL SERVIDOR ################## + '########## \\10.0.0.205\e$\Cargas\MOVIL\Lanterna ############ + '##################################################### + '/// En el servidor se necesita un archivo de texto (.ver) que tenga los siguientes + '/// datos separados por un tabulador. + '/// contents of ver file, each field is seperated by a tab + ' Field 0 = 2.226.19.09.19.01a <-- Esta es la version de la aplicación disponible + ' Field 1 = A new version of the MyAPP is available, Download and update now ? <-- Mensaje para cuando hay actualización + ' Field 2 = MyApp is up to date <--- Mensaje para cuando no hay actualización + ' Field 3 = http://www.mydomain.com/Public/myapp.apk <--- Liga al apk de la actualización + + Public nNewApp As Notification + Public nNewAppnID As Int = 16 + 'Para Download + Dim nativeMe As JavaObject + Dim n2 As Notification + Dim n2ID As Int = 16 + 'Para fileProvider + Public SharedFolder As String + Public UseFileProvider As Boolean + Private rp As RuntimePermissions + + Type mNewVersion(update As Boolean, nonewAPP As Boolean, notifyUser As Boolean, _ + version As String, newMsg As String, okMsg As String, appLink As String) + Public newApp As mNewVersion +End Sub + +Sub Service_Create + Log("appUpdater(), Service_Create") + newApp.Initialize + Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER + n2.Initialize + nativeMe.InitializeContext +End Sub + +Sub Service_Start (StartingIntent As Intent) + Log("appUpdater(), Service_Start") +' CallSubDelayed2(Main, "muestraProgreso", "Buscando actualización") + CallSubDelayed2(Main, "muestraProgreso", "Buscando actualización") +' B4XPages.MainPage.muestraProgreso("Buscando actualización") + Log("Buscando actualización") + fileProvider_init + Log(lnk) + Wait For (Download(Me, lnk)) JobDone (j As HttpJob) + If j.Success Then + Log("success") + Try + Dim app() As String = Regex.Split(Chr(9),j.GetString) + ' // Set the data + newApp.appLink = app(3) 'Liga a nueva app + newApp.newMsg = app(1) 'Texto de que hay actualizacion + newApp.okMsg = app(2) 'Texto de app al corriente + newApp.version = app(0) 'Version actual + + Log($"Application.VersionName=${Application.VersionName}, newApp=${newApp}"$) + + ' // App version check + If newApp.version = Application.VersionName Then + newApp.update = False + Log("No new app") +' B4XPages.ShowPage("updateAvailable") + StartActivity(updateAvailable) + 'Se puede mandar tambien una notificacion avisando que NO hay actualizaciones + CreateNotification2("Aplicacion al corriente","No hay actualizaciones disponibles","ic_file_download_white_24dp",Main,True,True,nNewApp,nNewAppnID) + End If + If newApp.version <> Application.VersionName Then + newApp.update = True + Log("New app true") +' B4XPages.ShowPage("updateAvailable") + StartActivity(updateAvailable) + 'Se puede mandar tambien una notificacion avisando que hay actualizacion disponible +' CreateNotification2("Nueva aplicación disponible","Haga clic para descargar.","ic_file_download_white_24dp",C_UpdateAvailable,True,True,nNewApp,nNewAppnID) + End If + Catch + Log("appUpdater(), Job Failed, error " & LastException.Message) + End Try + Else + Log("appUpdater(), Job Failed " & lnk) + End If + j.Release +' StopService(Me) +End Sub + +Sub download_Start (StartingIntent As Intent) + download_newApk +End Sub + +Sub download_newApk +' CreateNotification("Descargando actualización", "Descargando apk", "ic_file_download_white_24dp", Main, False, True) +' CallSubDelayed2(Main, "muestraProgreso", "Descargando actualización") + Log("Descargando actualización") +' B4XPages.ShowPage("login") + StartActivity(Main) + Starter.muestraProgreso = 1 + Dim job_newAPP As HttpJob + job_newAPP.Initialize("job_newAPP",Me) + job_newAPP.Download(newApp.appLink) + Wait for (job_newAPP) JobDone (job_newAPP As HttpJob) + If job_newAPP.Success = True Then + ' // Delete existing file + If File.Exists(SharedFolder,"newapp.apk") Then + File.Delete(SharedFolder,"newapp.apk") + End If + ' // Save new file + Dim outNewAPK As OutputStream = File.OpenOutput(SharedFolder,"newapp.apk", False) + File.Copy2(job_newAPP.GetInputStream, outNewAPK) + outNewAPK.Close + If Starter.Logger Then Log("APK dir: "&SharedFolder) + End If + job_newAPP.Release + ' // Install the app + Dim in As Intent + in.Initialize(in.ACTION_VIEW,"" ) + SetFileUriAsIntentData(in, "newapp.apk") + ' // Type must be set after calling SetFileUriAsIntentData + in.SetType("application/vnd.android.package-archive") + StartActivity(in) + n2.Cancel(nNewAppnID) +' B4XPages.MainPage.ocultaProgreso + CallSubDelayed(Main, "ocultaProgreso") +' Service.StopForeground(nNewAppnID) + StopService(Me) +' CallSubDelayed(Main,"ocultaProgreso") +End Sub + +Sub download_Destroy + n2.Cancel(n2ID) + Service.StopForeground(n2ID) +End Sub + +Sub Download (Callback As Object, link As String) As HttpJob + Dim j As HttpJob + j.Initialize("", Callback) + j.Download(link) + Return j +End Sub + +Private Sub CreateNotification2(Title As String, Content As String, _ 'ignore + Icon As String, TargetActivity As Object, Sound As Boolean, _ + Vibrate As Boolean, pN As Notification,pNID As Int) As Notification + pN.Initialize2(pN.IMPORTANCE_HIGH) +' pN.Number = pNID +' pN.Light = False + pN.Vibrate = Vibrate + pN.Sound = Sound +' pN.OnGoingEvent = False + pN.Icon = Icon + pN.AutoCancel = True + pN.SetInfo(Title, Content, TargetActivity) + pN.Notify(pNID) + Return pN +End Sub + +Private Sub CreateNotification(Title As String, Content As String, Icon As String, TargetActivity As Object, Sound As Boolean, Vibrate As Boolean) As Notification 'ignore + n2.Initialize + n2.Light = False + n2.Vibrate = Vibrate + n2.Sound = Sound + n2.OnGoingEvent = True + n2.Icon = Icon + n2.SetInfo(Title, Content, TargetActivity) + n2.Notify(nNewAppnID) +End Sub + +Sub Service_Destroy + Log("appUpdater(), Service_Destroy") +End Sub + +Sub fileProvider_init + Dim p As Phone + If p.SdkVersion >= 24 Or File.ExternalWritable = False Then + UseFileProvider = True + SharedFolder = File.Combine(File.DirInternal, "shared") + If Not(File.IsDirectory(File.DirInternal,"shared")) Then + File.MakeDir("", SharedFolder) + End If + Else + UseFileProvider = False + SharedFolder = rp.GetSafeDirDefaultExternal("shared") + End If + Log($"Using FileProvider? ${UseFileProvider}"$) +End Sub + +'Returns the file uri. +Sub GetFileUri (FileName As String) As Object + Try + If Not(UseFileProvider) Then + Dim uri As JavaObject + Return uri.InitializeStatic("android.net.Uri").RunMethod("parse", Array("file://" & File.Combine(SharedFolder, FileName))) + End If + Dim f As JavaObject + f.InitializeNewInstance("java.io.File", Array(SharedFolder, FileName)) + Dim fp As JavaObject + Dim context As JavaObject + context.InitializeContext + fp.InitializeStatic("android.support.v4.content.FileProvider") + Return fp.RunMethod("getUriForFile", Array(context, Application.PackageName & ".provider", f)) + Catch + Log("FileProvider::GetFileUri - error - " & LastException.Message) + Return "" + End Try +End Sub + +'Replaces the intent Data field with the file uri. +'Resets the type field. Make sure to call Intent.SetType after calling this method +Sub SetFileUriAsIntentData (Intent As Intent, FileName As String) + Dim jo As JavaObject = Intent + jo.RunMethod("setData", Array(GetFileUri(FileName))) + Intent.Flags = Bit.Or(Intent.Flags, 1) 'FLAG_GRANT_READ_URI_PERMISSION +End Sub diff --git a/updateAvailable.bas b/updateAvailable.bas new file mode 100644 index 0000000..82503cf --- /dev/null +++ b/updateAvailable.bas @@ -0,0 +1,77 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Activity +Version=12.8 +@EndOfDesignText@ +Sub Process_Globals +' Private Root As B4XView 'ignore +' Private xui As XUI 'ignore +End Sub + +Sub Globals + 'These global variables will be redeclared each time the activity is created. + 'These variables can only be accessed from this module. +End Sub + +'You can add more parameters here. +'Public Sub Initialize As Object +' Return Me +'End Sub + +'This event will be called once, before the page becomes visible. +Sub Activity_Create(FirstTime As Boolean) +' Root = Root1 + 'load the layout to Root + Activity.Color = Colors.Transparent +End Sub + +Sub Activity_Resume + Try + Do While Not(CanRequestPackageInstalls) + MsgboxAsync($"Por favor permita que ${Application.PackageName} instale actualizaciones"$, "Instalar actualización") + Wait For Msgbox_Result(Result As Int) + Dim in As Intent + in.Initialize("android.settings.MANAGE_UNKNOWN_APP_SOURCES", "package:" & Application.PackageName) + StartActivity(in) + Loop + Catch + Log("updateAvailable() Error - " & LastException.Message) + End Try + If appUpdater.newApp.update Then + ofreceActualizacion + Else + sinActualizacion + End If +End Sub + +'//////////////////////////////////////////////////////////////////////////////////////////// +'//// Esta es una actividad usada por el servicio appUpdater para mostrar notificaciones +'//// cuando hay alguna actualizacion de apk. +'//////////////////////////////////////////////////////////////////////////////////////////// + +public Sub CanRequestPackageInstalls As Boolean + ' // https://www.b4x.com/android/forum/threads/version-safe-apk-installation.87667/#content + Dim ctxt As JavaObject + ctxt.InitializeContext + Dim PackageManager As JavaObject = ctxt.RunMethod("getPackageManager", Null) + Return PackageManager.RunMethod("canRequestPackageInstalls", Null) +End Sub + +Sub ofreceActualizacion + If Msgbox2(appUpdater.newApp.newMsg,"Actualización disponible","Si","","No",Null) = DialogResponse.Positive Then 'ignore +' StartService(DownloadService) + CallSubDelayed(appUpdater, "download_newApk") + End If + CallSubDelayed(Main, "ocultaProgreso") + StartActivity(Main) +' Activity.Finish +' B4XPages.ShowPage("Login") +End Sub + +Sub sinActualizacion + Msgbox(appUpdater.newApp.okMsg, "Aplicación al corriente") 'ignore + CallSubDelayed(Main, "ocultaProgreso") + StartActivity(Main) +' B4XPages.ShowPage("Login") +End Sub \ No newline at end of file