1angular.module('appInstallationServices', []) 2 .service('AppInstallationService', function($window, $q, growlService) { 3 4 var self = this; 5 6 /** 7 * Detecta si la aplicación está instalada como PWA 8 * @returns {Promise<boolean>} Promesa que resuelve con true si está instalada, false si no 9 */ 10 this.isAppInstalled = function() { 11 var deferred = $q.defer(); 12 13 try { 14 // Método 1: Verificar si está en modo standalone (iOS) 15 if ($window.navigator.standalone === true) { 16 deferred.resolve(true); 17 return deferred.promise; 18 } 19 20 // Método 2: Verificar display-mode CSS (Android y otros) 21 if ($window.matchMedia && $window.matchMedia('(display-mode: standalone)').matches) { 22 deferred.resolve(true); 23 return deferred.promise; 24 } 25 26 // Método 3: Verificar si la app fue lanzada desde la pantalla de inicio 27 if ($window.matchMedia && $window.matchMedia('(display-mode: minimal-ui)').matches) { 28 deferred.resolve(true); 29 return deferred.promise; 30 } 31 32 // Método 4: Verificar user agent especÃfico de TWA (Trusted Web Activity) 33 var userAgent = $window.navigator.userAgent || ''; 34 if (userAgent.includes('wv')) { // WebView indicator 35 deferred.resolve(true); 36 return deferred.promise; 37 } 38 39 if (!$window.deferredPrompt) { 40 deferred.resolve(true); 41 return deferred.promise; 42 } 43 44 // Si ningún método detecta instalación 45 deferred.resolve(false); 46 47 } catch (error) { 48 console.error('Error al detectar instalación de la app:', error); 49 deferred.reject(error); 50 } 51 52 return deferred.promise; 53 }; 54 55 /** 56 * Verifica si la app puede ser instalada (muestra el prompt de instalación) 57 * @returns {boolean} true si puede ser instalada, false si no 58 */ 59 this.canBeInstalled = function() { 60 // Verificar si hay un evento beforeinstallprompt guardado 61 return !!$window.deferredPrompt; 62 }; 63 64 /** 65 * Muestra el prompt de instalación si está disponible 66 * @returns {Promise<boolean>} Promesa que resuelve con true si el usuario acepta instalar 67 */ 68 this.showInstallPrompt = function() { 69 var deferred = $q.defer(); 70 71 // Primero verificar si la app ya está instalada 72 self.isAppInstalled().then(function(isInstalled) { 73 if (isInstalled) { 74 _cio.track("app_install_already_installed"); 75 console.log('La aplicación ya está instalada'); 76 growlService.growl('La aplicación ya está instalada', 'info'); 77 deferred.resolve(false); 78 return; 79 } 80 81 // Verificar si el prompt está disponible 82 if (!$window.deferredPrompt) { 83 _cio.track("app_install_not_available"); 84 console.log('El prompt de instalación no está disponible'); 85 deferred.resolve(false); 86 return; 87 } 88 89 // Mostrar el prompt 90 $window.deferredPrompt.prompt(); 91 92 // Esperar la respuesta del usuario 93 $window.deferredPrompt.userChoice.then(function(choiceResult) { 94 _cio.track("app_install"); 95 if (choiceResult.outcome === 'accepted') { 96 _cio.track("app_install_accepted"); 97 deferred.resolve(true); 98 } else { 99 _cio.track("app_install_rejected"); 100 deferred.resolve(false); 101 } 102 // Limpiar el prompt después de usarlo 103 $window.deferredPrompt = null; 104 }).catch(function(error) { 105 _cio.track("app_install_error"); 106 console.error('Error en el prompt de instalación:', error); 107 deferred.reject(error); 108 }); 109 }).catch(function(error) { 110 _cio.track("app_install_check_error"); 111 console.error('Error al verificar si la app está instalada:', error); 112 deferred.reject(error); 113 }); 114 115 return deferred.promise; 116 }; 117 118 /** 119 * Obtiene información detallada sobre el estado de instalación 120 * @returns {Promise<Object>} Promesa con objeto conteniendo información detallada 121 */ 122 this.getInstallationInfo = function() { 123 var deferred = $q.defer(); 124 125 self.isAppInstalled().then(function(isInstalled) { 126 var info = { 127 isInstalled: isInstalled, 128 canBeInstalled: self.canBeInstalled(), 129 isStandalone: $window.navigator.standalone === true, 130 displayMode: null, 131 userAgent: $window.navigator.userAgent || '', 132 platform: $window.navigator.platform || '', 133 timestamp: new Date().toISOString() 134 }; 135 136 // Detectar el modo de visualización actual 137 if ($window.matchMedia) { 138 if ($window.matchMedia('(display-mode: standalone)').matches) { 139 info.displayMode = 'standalone'; 140 } else if ($window.matchMedia('(display-mode: minimal-ui)').matches) { 141 info.displayMode = 'minimal-ui'; 142 } else if ($window.matchMedia('(display-mode: fullscreen)').matches) { 143 info.displayMode = 'fullscreen'; 144 } else { 145 info.displayMode = 'browser'; 146 } 147 } 148 149 deferred.resolve(info); 150 }).catch(function(error) { 151 deferred.reject(error); 152 }); 153 154 return deferred.promise; 155 }; 156 157 /** 158 * Inicializa los listeners para eventos de instalación 159 */ 160 this.initInstallationListeners = function() { 161 // Listener para el evento beforeinstallprompt 162 $window.addEventListener('beforeinstallprompt', function(e) { 163 console.log('Evento beforeinstallprompt disparado'); 164 // Prevenir que se muestre automáticamente 165 e.preventDefault(); 166 // Guardar el evento para usarlo más tarde 167 $window.deferredPrompt = e; 168 }); 169 170 // Listener para cuando la app es instalada 171 $window.addEventListener('appinstalled', function(e) { 172 console.log('App instalada exitosamente'); 173 // Limpiar el prompt guardado 174 $window.deferredPrompt = null;
175 // Aquà puedes disparar eventos personalizados o notificaciones 176 }); 177 }; 178 179 // Inicializar listeners automáticamente 180 this.initInstallationListeners(); 181 });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.