{"_id":"@ahmed-mili/capacitor-thunder-bg-service","_rev":"5-f9f9fc9bb5b1895ea4fc4c3cf5f11efe","name":"@ahmed-mili/capacitor-thunder-bg-service","dist-tags":{"latest":"0.1.31"},"versions":{"0.1.0":{"name":"@ahmed-mili/capacitor-thunder-bg-service","version":"0.1.0","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"author":{"name":"Webify"},"license":"MIT","_id":"@ahmed-mili/capacitor-thunder-bg-service@0.1.0","maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"homepage":"https://github.com/webify/capacitor-thunder-bg-service#readme","bugs":{"url":"https://github.com/webify/capacitor-thunder-bg-service/issues"},"dist":{"shasum":"5a28a092418839a9f8b6f58f685e907c3031b507","tarball":"https://registry.npmjs.org/@ahmed-mili/capacitor-thunder-bg-service/-/capacitor-thunder-bg-service-0.1.0.tgz","fileCount":78,"integrity":"sha512-dsUbKUTuvOysUTM/j2mdeFe8tqq/qrVcHitLsV15XOz6NHfNFmV8TvjEF6tNeKsJpPk0OqgjzIH+3cIuRw9wBQ==","signatures":[{"sig":"MEQCIBrB5tMa3dAuvQwuMcLqbznaPVF5l1U2KTgN3sboDQL2AiAVzENMAduLf9EY6sKdoLQAqsVa9tXg2BZ0ze7tLkA7tg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":273473},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"5c2f6e91c4c6df08cfdde2cda76cf6f95c7d70d5","scripts":{"build":"tsc -p tsconfig.json","clean":"rimraf dist","prepare":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/webify/capacitor-thunder-bg-service.git","type":"git"},"_npmVersion":"11.6.2","description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.6.3","@capacitor/core":"^7.0.0"},"peerDependencies":{"@capacitor/core":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-thunder-bg-service_0.1.0_1762266885109_0.5573862629246067","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ahmed-mili/capacitor-thunder-bg-service","version":"0.1.1","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"author":{"name":"Webify"},"license":"MIT","_id":"@ahmed-mili/capacitor-thunder-bg-service@0.1.1","maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"homepage":"https://github.com/ahmedmili/thunderbgservice#readme","bugs":{"url":"https://github.com/ahmedmili/thunderbgservice/issues"},"dist":{"shasum":"8f63e0579c3e4fdf19507195fc777c966fb3eb01","tarball":"https://registry.npmjs.org/@ahmed-mili/capacitor-thunder-bg-service/-/capacitor-thunder-bg-service-0.1.1.tgz","fileCount":78,"integrity":"sha512-BitRd609QVMwCOsgJIFfvEJNS5xcveRrP8ak2O0OiqKNI2MZDTAMiecFXVdtAoORzqEKyMLS7I3FrCv8W5kJ7w==","signatures":[{"sig":"MEUCIQCDvS+h7z/pYKzQT9aPXIvsFNSXmv6nIn54JRtkfTvwbAIgarWX0yqMl8Abu2VqJYgaeqISLk2m5SQe8pMQvIlGyjk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":273446},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"5c2f6e91c4c6df08cfdde2cda76cf6f95c7d70d5","scripts":{"build":"tsc -p tsconfig.json","clean":"rimraf dist","prepare":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/ahmedmili/thunderbgservice.git","type":"git"},"_npmVersion":"11.6.2","description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.6.3","@capacitor/core":"^7.0.0"},"peerDependencies":{"@capacitor/core":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-thunder-bg-service_0.1.1_1762267227638_0.166115760836971","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@ahmed-mili/capacitor-thunder-bg-service","version":"0.1.2","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"author":{"name":"Webify"},"license":"MIT","_id":"@ahmed-mili/capacitor-thunder-bg-service@0.1.2","maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"homepage":"https://github.com/ahmedmili/thunderbgservice#readme","bugs":{"url":"https://github.com/ahmedmili/thunderbgservice/issues"},"dist":{"shasum":"95832c0fa8e144b57e6472d071527df50f1730c3","tarball":"https://registry.npmjs.org/@ahmed-mili/capacitor-thunder-bg-service/-/capacitor-thunder-bg-service-0.1.2.tgz","fileCount":2357,"integrity":"sha512-fGO8Jwx9gYBobl3p2DbkolZOHw6znwHCFMHAC8+H/C0j2c1Nl+KBzVOfRrZ0AE+w/Wt9puEPj+7KzseDGQUBvQ==","signatures":[{"sig":"MEYCIQC+kz7Vxfnr3OjLiO79KN9PA/synJA1U7d4OlLoDuk1xwIhAKACT2g7iZp60tBfUU+kNB/pWomBSsmdu2nzG9CV3mrT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":17149693},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"1c15d3a7a2968527f2c59cf5edefa5180888dc2b","scripts":{"build":"tsc -p tsconfig.json","clean":"rimraf dist","prepare":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/ahmedmili/thunderbgservice.git","type":"git"},"_npmVersion":"11.6.2","description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.6.3","@capacitor/core":"^7.0.0"},"peerDependencies":{"@capacitor/core":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-thunder-bg-service_0.1.2_1762355897730_0.3198086421420363","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@ahmed-mili/capacitor-thunder-bg-service","version":"0.1.3","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"author":{"name":"Webify"},"license":"MIT","_id":"@ahmed-mili/capacitor-thunder-bg-service@0.1.3","maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"homepage":"https://github.com/ahmedmili/thunderbgservice#readme","bugs":{"url":"https://github.com/ahmedmili/thunderbgservice/issues"},"dist":{"shasum":"9f3b4b07689fe3dabd81dc976a92b98ced761d0d","tarball":"https://registry.npmjs.org/@ahmed-mili/capacitor-thunder-bg-service/-/capacitor-thunder-bg-service-0.1.3.tgz","fileCount":2433,"integrity":"sha512-BNR/UP6gCASl2yfdSnjdseTshw9wel2pLxdytaNe4gcGDXRhuHw4l28xcuUgXIDGbM5NRPHwH0DaKZKoDc+IAQ==","signatures":[{"sig":"MEQCICBznIIz9OumPyETfRKlJcUuOa4bdzSddXvA8TVJ5acSAiAUnJ0wUNt8KC9mxIA8jAeTfVWVd0QoTWLmWkd+5IYqQA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":17651415},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"dbfd621b41d2f49a0cbec0bba86786200ed70966","scripts":{"docs":"typedoc src/index.ts --out docs/api","lint":"eslint src/**/*.ts","test":"jest","build":"tsc -p tsconfig.json","clean":"rimraf dist","prepare":"npm run build","lint:fix":"eslint src/**/*.ts --fix","docs:watch":"typedoc --watch src/index.ts --out docs/api","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/ahmedmili/thunderbgservice.git","type":"git"},"_npmVersion":"11.6.2","description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.56.0","rimraf":"^5.0.5","ts-jest":"^29.1.2","typedoc":"^0.26.0","typescript":"^5.6.3","@types/jest":"^29.5.12","@capacitor/core":"^7.0.0","@typescript-eslint/parser":"^6.21.0","@typescript-eslint/eslint-plugin":"^6.21.0"},"peerDependencies":{"@capacitor/core":"^7.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-thunder-bg-service_0.1.3_1762425353985_0.705187350951406","host":"s3://npm-registry-packages-npm-production"}},"0.1.31":{"name":"@ahmed-mili/capacitor-thunder-bg-service","version":"0.1.31","description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","main":"dist/index.js","types":"dist/index.d.ts","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"author":{"name":"Webify"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/ahmedmili/thunderbgservice.git"},"bugs":{"url":"https://github.com/ahmedmili/thunderbgservice/issues"},"homepage":"https://github.com/ahmedmili/thunderbgservice#readme","scripts":{"build":"tsc -p tsconfig.json","clean":"rimraf dist","prepare":"npm run build","prepublishOnly":"npm run build","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix","docs":"typedoc src/index.ts --out docs/api","docs:watch":"typedoc --watch src/index.ts --out docs/api"},"capacitor":{"android":{"src":"android"},"ios":{"src":"ios"}},"peerDependencies":{"@capacitor/core":"^7.0.0"},"devDependencies":{"@capacitor/core":"^7.0.0","typescript":"^5.6.3","rimraf":"^5.0.5","@types/jest":"^29.5.12","@typescript-eslint/eslint-plugin":"^6.21.0","@typescript-eslint/parser":"^6.21.0","eslint":"^8.56.0","jest":"^29.7.0","ts-jest":"^29.1.2","typedoc":"^0.26.0"},"gitHead":"443f9000826f2dbce7854ceb0f47efa0b44b6c77","_id":"@ahmed-mili/capacitor-thunder-bg-service@0.1.31","_nodeVersion":"22.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-S+eTJn7QQZyTyV8QLNHBnnpxbCgOxRjxSMz2XtavyU2jtib2P8PuqVGqYjbgx7FBj4zhnOBMg65d36NNmPvtPg==","shasum":"411247214de13fbcec701190a1f0cfc434470c92","tarball":"https://registry.npmjs.org/@ahmed-mili/capacitor-thunder-bg-service/-/capacitor-thunder-bg-service-0.1.31.tgz","fileCount":176,"unpackedSize":1134738,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICxCLVi2Fg31+RuCAPoOKPRMJl/ZfdLlMB/glkFJE3q1AiAdROtSodvIKabvNXvXDEnP9tpQKCvP/aSuBF1w5eQDIg=="}]},"_npmUser":{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"},"directories":{},"maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/capacitor-thunder-bg-service_0.1.31_1762440153176_0.8877248646745057"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-04T14:34:45.012Z","modified":"2025-11-06T14:42:33.566Z","0.1.0":"2025-11-04T14:34:45.311Z","0.1.1":"2025-11-04T14:40:27.845Z","0.1.2":"2025-11-05T15:18:18.035Z","0.1.3":"2025-11-06T10:35:54.285Z","0.1.31":"2025-11-06T14:42:33.368Z"},"bugs":{"url":"https://github.com/ahmedmili/thunderbgservice/issues"},"author":{"name":"Webify"},"license":"MIT","homepage":"https://github.com/ahmedmili/thunderbgservice#readme","keywords":["capacitor","plugin","android","foreground-service","notification","background-tasks","location","gps","tracking","ionic","capacitor-7"],"repository":{"type":"git","url":"git+https://github.com/ahmedmili/thunderbgservice.git"},"description":"Capacitor 7 plugin - Android foreground service with notification, location tracking, and background tasks.","maintainers":[{"name":"ahmed-mili","email":"ahmedmili76@gmail.com"}],"readme":"# @ahmed-mili/capacitor-thunder-bg-service\r\n\r\nPlugin Capacitor 7 pour Android qui fournit un service foreground avec notifications, localisation, et gestion de tâches en arrière-plan. Fonctionne même quand l'app est fermée.\r\n\r\n## ✨ Fonctionnalités principales\r\n\r\n- **UI 100% dynamique depuis l'app** : Injection complète de layouts, textes et boutons depuis votre application\r\n- **Boutons cliquables dans la notification** : Boutons interactifs reliés à vos BroadcastReceiver\r\n- **Persistance d'état** : L'UI et l'état persistent même après fermeture/réouverture de l'app\r\n- **Tâches en arrière-plan** : Exécution de code Java même si l'app est fermée\r\n- **Localisation** : Suivi GPS en arrière-plan\r\n- **Aucune UI/logique par défaut** : Le plugin n'affiche que ce que vous envoyez depuis l'app\r\n\r\n## 📋 Table des matières\r\n\r\n1. [Installation](#installation)\r\n2. [Configuration](#configuration)\r\n3. [Utilisation de base](#utilisation-de-base)\r\n4. [Notifications personnalisées](#notifications-personnalisées)\r\n5. [UI Dynamique 100% App-Driven](#-ui-dynamique-100-app-driven)\r\n6. [Tâches en arrière-plan](#tâches-en-arrière-plan)\r\n7. [Localisation](#localisation)\r\n8. [Utilisation depuis Java natif](#utilisation-depuis-java-natif)\r\n9. [API complète](#api-complète)\r\n10. [Architecture](#architecture)\r\n11. [Exemples](#exemples)\r\n12. [Dépannage](#dépannage)\r\n\r\n---\r\n\r\n## 🚀 Installation\r\n\r\n### 1. Installer le package\r\n\r\n```bash\r\nnpm install @ahmed-mili/capacitor-thunder-bg-service\r\n```\r\n\r\n### 2. Synchroniser avec Capacitor\r\n\r\n```bash\r\nnpx cap sync android\r\n```\r\n\r\n### 3. Permissions Android\r\n\r\nLe plugin nécessite les permissions suivantes (déjà incluses dans le plugin) :\r\n- `FOREGROUND_SERVICE`\r\n- `FOREGROUND_SERVICE_LOCATION`\r\n- `POST_NOTIFICATIONS`\r\n- `ACCESS_FINE_LOCATION`\r\n- `ACCESS_COARSE_LOCATION`\r\n- `INTERNET`\r\n- `WAKE_LOCK`\r\n\r\n### 4. Configuration des ressources Android (Requis)\r\n\r\n**Le plugin ne contient aucune UI par défaut.** Vous devez créer vos propres layouts dans votre app.\r\n\r\n**Layout de notification** (`android/app/src/main/res/layout/notification_online.xml` - exemple) :\r\n```xml\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"wrap_content\"\r\n    android:orientation=\"vertical\"\r\n    android:padding=\"12dp\">\r\n    <TextView\r\n        android:id=\"@+id/txtDriverStatus\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"En ligne\"\r\n        android:textStyle=\"bold\"\r\n        android:textSize=\"16sp\" />\r\n    <TextView\r\n        android:id=\"@+id/txtWaiting\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"En attente\"\r\n        android:textSize=\"14sp\" />\r\n    <Button\r\n        android:id=\"@+id/btnAction\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"Action\" />\r\n</LinearLayout>\r\n```\r\n\r\n**Icône de notification** (`android/app/src/main/res/drawable/ic_notification.xml`) :\r\n```xml\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:width=\"24dp\"\r\n    android:height=\"24dp\"\r\n    android:viewportWidth=\"24\"\r\n    android:viewportHeight=\"24\">\r\n    <path\r\n        android:fillColor=\"#FF000000\"\r\n        android:pathData=\"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z\"/>\r\n</vector>\r\n```\r\n\r\n**Important** : Créez vos layouts dans `android/app/src/main/res/layout/` de votre app. Le plugin utilisera uniquement les layouts que vous spécifiez via `customLayout`.\r\n\r\n### 5. Configuration minimale\r\n\r\nAucune autre configuration n'est requise. Le plugin est prêt à l'emploi.\r\n\r\n---\r\n\r\n## ⚙️ Configuration\r\n\r\n### Permissions Runtime (Android 6+)\r\n\r\nVous devez demander les permissions à l'utilisateur :\r\n\r\n```typescript\r\nimport { Permissions } from '@capacitor/core';\r\n\r\nasync function requestPermissions() {\r\n  const permissions = await Permissions.request([\r\n    Permissions.ANDROID.POST_NOTIFICATIONS,\r\n    Permissions.ANDROID.ACCESS_FINE_LOCATION,\r\n    Permissions.ANDROID.ACCESS_COARSE_LOCATION,\r\n  ]);\r\n  return permissions;\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🎯 Utilisation de base\r\n\r\n### 1. Démarrer le service\r\n\r\n**Important** : Vous devez toujours fournir `customLayout` car le plugin n'a pas de UI par défaut.\r\n\r\n```typescript\r\nimport { ThunderBgService } from '@ahmed-mili/capacitor-thunder-bg-service';\r\n\r\n// Démarrer avec un layout personnalisé\r\nawait ThunderBgService.start({\r\n  customLayout: 'notification_online',  // REQUIS : nom de votre layout XML\r\n  titleViewId: 'txtDriverStatus',       // ID du TextView pour le titre\r\n  subtitleViewId: 'txtWaiting',        // ID du TextView pour le sous-titre\r\n  notificationTitle: 'Online',\r\n  notificationSubtitle: 'Service actif',\r\n  enableLocation: true,\r\n  soundsEnabled: false,\r\n});\r\n```\r\n\r\n### 2. Mettre à jour la notification\r\n\r\n```typescript\r\n// Mettre à jour le contenu de la notification\r\nawait ThunderBgService.update({\r\n  notificationTitle: 'En cours',\r\n  notificationSubtitle: 'Traitement des données',\r\n});\r\n```\r\n\r\n### 3. Arrêter le service\r\n\r\n```typescript\r\n// Arrêter le service et toutes les tâches\r\nawait ThunderBgService.stop();\r\n```\r\n\r\n### 4. Exemple complet dans un service Angular\r\n\r\n```typescript\r\nimport { Injectable } from '@angular/core';\r\nimport { ThunderBgService } from '@ahmed-mili/capacitor-thunder-bg-service';\r\n\r\n@Injectable({\r\n  providedIn: 'root'\r\n})\r\nexport class BackgroundService {\r\n  \r\n  async startService() {\r\n    try {\r\n      await ThunderBgService.start({\r\n        notificationTitle: 'Online',\r\n        notificationSubtitle: 'Service actif',\r\n        enableLocation: true,\r\n        customLayout: 'notification_online',  // REQUIS : layout personnalisé\r\n        titleViewId: 'txtTitle',\r\n        subtitleViewId: 'txtSubtitle',\r\n      });\r\n      console.log('Service démarré');\r\n    } catch (error) {\r\n      console.error('Erreur:', error);\r\n    }\r\n  }\r\n  \r\n  async updateStatus(status: string) {\r\n    await ThunderBgService.update({\r\n      notificationSubtitle: status,\r\n    });\r\n  }\r\n  \r\n  async stopService() {\r\n    await ThunderBgService.stop();\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🎨 Notifications personnalisées\r\n\r\n### 1. Layout personnalisé (Requis)\r\n\r\n**⚠️ Important** : Le plugin n'a **pas de layout par défaut**. Vous devez créer votre propre layout XML dans votre application.\r\n\r\nLe plugin peut utiliser un layout de fallback si aucun `customLayout` n'est fourni, mais il est **fortement recommandé** de toujours fournir un `customLayout` pour un contrôle total de l'UI.\r\n\r\n### 2. Créer votre propre layout\r\n\r\nCréez un fichier XML dans `android/app/src/main/res/layout/` :\r\n\r\n```xml\r\n<!-- notification_custom.xml -->\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"wrap_content\"\r\n    android:orientation=\"vertical\"\r\n    android:padding=\"12dp\">\r\n\r\n    <TextView\r\n        android:id=\"@+id/txtTitle\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"Title\"\r\n        android:textStyle=\"bold\"\r\n        android:textSize=\"16sp\"\r\n        android:textColor=\"#000000\" />\r\n\r\n    <TextView\r\n        android:id=\"@+id/txtSubtitle\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"Subtitle\"\r\n        android:textSize=\"14sp\"\r\n        android:textColor=\"#444444\" />\r\n\r\n    <TextView\r\n        android:id=\"@+id/txtTimer\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"00:00:00\"\r\n        android:textSize=\"13sp\"\r\n        android:textColor=\"#1B5E20\" />\r\n</LinearLayout>\r\n```\r\n\r\n### 3. Utiliser le layout personnalisé\r\n\r\n```typescript\r\n// Démarrer avec un layout personnalisé\r\nawait ThunderBgService.start({\r\n  notificationTitle: 'Online',\r\n  notificationSubtitle: 'En attente',\r\n  enableLocation: true,\r\n  customLayout: 'notification_custom',     // Nom du layout (sans .xml)\r\n  titleViewId: 'txtTitle',                 // ID du TextView pour le titre\r\n  subtitleViewId: 'txtSubtitle',          // ID du TextView pour le sous-titre\r\n  timerViewId: 'txtTimer',                 // ID du TextView pour le timer\r\n});\r\n```\r\n\r\n### 4. Changer de layout dynamiquement\r\n\r\n```typescript\r\n// Changer de layout sans redémarrer le service\r\nawait ThunderBgService.update({\r\n  notificationTitle: 'Nouveau titre',\r\n  notificationSubtitle: 'Nouveau sous-titre',\r\n  customLayout: 'notification_other',      // Nouveau layout\r\n  titleViewId: 'txtOtherTitle',            // Nouveaux IDs\r\n  subtitleViewId: 'txtOtherSubtitle',\r\n  timerViewId: 'txtOtherTimer',\r\n});\r\n```\r\n\r\n### 5. Exemple : Layouts multiples selon l'état\r\n\r\n```typescript\r\nenum AppState {\r\n  OFFLINE = 'offline',\r\n  ONLINE = 'online',\r\n  ON_RIDE = 'on_ride',\r\n  ARRIVED = 'arrived',\r\n}\r\n\r\nclass NotificationManager {\r\n  async switchToState(state: AppState) {\r\n    const configs = {\r\n      [AppState.OFFLINE]: {\r\n        title: 'Hors ligne',\r\n        subtitle: 'Service arrêté',\r\n        layout: 'notification_offline',\r\n        titleId: 'txtStatus',\r\n        subtitleId: 'txtMessage',\r\n      },\r\n      [AppState.ONLINE]: {\r\n        title: 'En ligne',\r\n        subtitle: 'En attente de courses',\r\n        layout: 'notification_online',\r\n        titleId: 'txtDriverStatus',\r\n        subtitleId: 'txtWaiting',\r\n      },\r\n      [AppState.ON_RIDE]: {\r\n        title: 'En course',\r\n        subtitle: 'Direction destination',\r\n        layout: 'notification_riding',\r\n        titleId: 'txtRideStatus',\r\n        subtitleId: 'txtDestination',\r\n      },\r\n      [AppState.ARRIVED]: {\r\n        title: 'Arrivé',\r\n        subtitle: 'À destination',\r\n        layout: 'notification_arrived',\r\n        titleId: 'txtArrivalStatus',\r\n        subtitleId: 'txtLocation',\r\n      },\r\n    };\r\n    \r\n    const config = configs[state];\r\n    await ThunderBgService.update({\r\n      notificationTitle: config.title,\r\n      notificationSubtitle: config.subtitle,\r\n      customLayout: config.layout,\r\n      titleViewId: config.titleId,\r\n      subtitleViewId: config.subtitleId,\r\n    });\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🎨 UI Dynamique 100% App-Driven\r\n\r\nLe plugin ne contient **aucune UI ou logique par défaut**. Tout doit être fourni depuis votre application.\r\n\r\n### 1. Injection dynamique de textes (viewData)\r\n\r\nUtilisez `viewData` pour mettre à jour n'importe quel TextView de votre layout :\r\n\r\n```typescript\r\nawait ThunderBgService.update({\r\n  customLayout: 'notification_online',\r\n  viewData: {\r\n    txtDriverStatus: 'En ligne',\r\n    txtWaiting: 'En attente de courses',\r\n    txtTimer: '00:05:23',\r\n    // Ajoutez autant de TextViews que vous voulez\r\n  },\r\n});\r\n```\r\n\r\n**Important** : Les IDs dans `viewData` doivent correspondre exactement aux IDs de votre XML (sans `@+id/`).\r\n\r\n### 2. Boutons cliquables dans la notification (buttons)\r\n\r\nCréez des boutons interactifs reliés à vos BroadcastReceiver :\r\n\r\n```typescript\r\nawait ThunderBgService.update({\r\n  customLayout: 'notification_stepper',\r\n  buttons: [\r\n    {\r\n      viewId: 'btnPrev',  // ID du Button/TextView dans votre XML\r\n      action: 'com.yourapp.ACTION_STEPPER_PREV',  // Action broadcast\r\n    },\r\n    {\r\n      viewId: 'btnNext',\r\n      action: 'com.yourapp.ACTION_STEPPER_NEXT',\r\n    },\r\n    {\r\n      viewId: 'btnDone',\r\n      action: 'com.yourapp.ACTION_ONLINE',\r\n      extras: {  // Optionnel : données supplémentaires\r\n        step: '3',\r\n        status: 'completed',\r\n      },\r\n    },\r\n  ],\r\n});\r\n```\r\n\r\n**⚠️ Important** : Les boutons doivent être **re-fournis à chaque appel à `update()`** car les instances de `RemoteViews` sont recréées. Si vous omettez `buttons` dans un `update()`, les boutons perdront leurs bindings de clics.\r\n\r\n### 3. Configuration du BroadcastReceiver\r\n\r\nDans votre `AndroidManifest.xml` :\r\n\r\n```xml\r\n<receiver \r\n    android:name=\".NotifActionReceiver\"\r\n    android:exported=\"true\"\r\n    android:enabled=\"true\">\r\n    <intent-filter>\r\n        <action android:name=\"com.yourapp.ACTION_STEPPER_PREV\"/>\r\n        <action android:name=\"com.yourapp.ACTION_STEPPER_NEXT\"/>\r\n        <action android:name=\"com.yourapp.ACTION_ONLINE\"/>\r\n        <!-- Ajoutez toutes vos actions -->\r\n    </intent-filter>\r\n</receiver>\r\n```\r\n\r\nDans votre `NotifActionReceiver.java` :\r\n\r\n```java\r\npublic class NotifActionReceiver extends BroadcastReceiver {\r\n    @Override\r\n    public void onReceive(Context context, Intent intent) {\r\n        String action = intent.getAction();\r\n        if (\"com.yourapp.ACTION_STEPPER_PREV\".equals(action)) {\r\n            // Votre logique\r\n        } else if (\"com.yourapp.ACTION_STEPPER_NEXT\".equals(action)) {\r\n            // Votre logique\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n### 4. Exemple complet : Page stepper avec boutons\r\n\r\n**Layout XML** (`notification_stepper.xml`) :\r\n\r\n```xml\r\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"wrap_content\"\r\n    android:orientation=\"vertical\"\r\n    android:padding=\"12dp\">\r\n    \r\n    <TextView\r\n        android:id=\"@+id/txtTitle\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"Étapes\"\r\n        android:textStyle=\"bold\" />\r\n    \r\n    <TextView\r\n        android:id=\"@+id/txtCurrentStep\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:text=\"Étape actuelle: 1/3\" />\r\n    \r\n    <LinearLayout\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:orientation=\"horizontal\">\r\n        \r\n        <Button\r\n            android:id=\"@+id/btnPrev\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:text=\"Précédent\" />\r\n        \r\n        <Button\r\n            android:id=\"@+id/btnNext\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:text=\"Suivant\" />\r\n    </LinearLayout>\r\n</LinearLayout>\r\n```\r\n\r\n**TypeScript** :\r\n\r\n```typescript\r\n// Démarrer avec page stepper\r\nawait ThunderBgService.start({\r\n  customLayout: 'notification_stepper',\r\n  titleViewId: 'txtTitle',\r\n  subtitleViewId: 'txtCurrentStep',\r\n  viewData: {\r\n    txtTitle: 'Étapes',\r\n    txtCurrentStep: 'Étape actuelle: 1/3',\r\n  },\r\n  buttons: [\r\n    { viewId: 'btnPrev', action: 'com.yourapp.ACTION_STEPPER_PREV' },\r\n    { viewId: 'btnNext', action: 'com.yourapp.ACTION_STEPPER_NEXT' },\r\n  ],\r\n});\r\n\r\n// Mettre à jour dynamiquement\r\nawait ThunderBgService.update({\r\n  viewData: {\r\n    txtCurrentStep: 'Étape actuelle: 2/3',\r\n  },\r\n});\r\n```\r\n\r\n**Java Helper** (dans votre app) :\r\n\r\n```java\r\npublic class NotificationDynamicHelper {\r\n    private int currentStep = 1;\r\n    \r\n    public void stepNext() {\r\n        currentStep = Math.min(3, currentStep + 1);\r\n        updateStepperUI();\r\n    }\r\n    \r\n    private void updateStepperUI() {\r\n        Intent extras = new Intent();\r\n        extras.putExtra(FgConstants.EXTRA_CUSTOM_LAYOUT, \"notification_stepper\");\r\n        extras.putExtra(FgConstants.EXTRA_TITLE_VIEW_ID, \"txtTitle\");\r\n        extras.putExtra(FgConstants.EXTRA_SUBTITLE_VIEW_ID, \"txtCurrentStep\");\r\n        \r\n        JSONObject viewData = new JSONObject();\r\n        viewData.put(\"txtTitle\", \"Étapes\");\r\n        viewData.put(\"txtCurrentStep\", \"Étape actuelle: \" + currentStep + \"/3\");\r\n        extras.putExtra(FgConstants.EXTRA_VIEW_DATA_JSON, viewData.toString());\r\n        \r\n        JSONArray buttons = new JSONArray();\r\n        buttons.put(new JSONObject().put(\"viewId\", \"btnPrev\").put(\"action\", \"com.yourapp.ACTION_STEPPER_PREV\"));\r\n        buttons.put(new JSONObject().put(\"viewId\", \"btnNext\").put(\"action\", \"com.yourapp.ACTION_STEPPER_NEXT\"));\r\n        extras.putExtra(FgConstants.EXTRA_BUTTONS_JSON, buttons.toString());\r\n        \r\n        ForegroundTaskService.startAction(context, FgConstants.ACTION_UPDATE, extras);\r\n    }\r\n}\r\n```\r\n\r\n### 5. Persistance automatique\r\n\r\nLe plugin sauvegarde automatiquement :\r\n- Le layout actuel (`customLayout`)\r\n- Les IDs de vues (`titleViewId`, `subtitleViewId`, `timerViewId`)\r\n- Les données dynamiques (`viewData`)\r\n- Les boutons (`buttons`)\r\n\r\nQuand vous fermez et rouvrez l'app, l'UI est automatiquement restaurée à l'état précédent.\r\n\r\n### 6. Notes importantes\r\n\r\n- **Aucun layout par défaut** : Vous devez toujours fournir `customLayout`\r\n- **IDs exacts** : Les IDs dans `viewData` et `buttons` doivent correspondre exactement à votre XML\r\n- **Boutons cliquables** : Utilisez `Button` ou `TextView` avec `android:clickable=\"true\"`\r\n- **Receiver exporté** : `android:exported=\"true\"` est obligatoire sur Android 12+\r\n\r\n---\r\n\r\n## 🔄 Tâches en arrière-plan\r\n\r\n### 1. Concept\r\n\r\nLes tâches en arrière-plan sont des fonctions Java qui s'exécutent périodiquement **même si l'app est fermée**. Elles tournent dans le service foreground.\r\n\r\n### 2. Créer une tâche\r\n\r\nCréez une classe Java dans votre app qui implémente `BackgroundTask` :\r\n\r\n```java\r\npackage com.yourpackage;\r\n\r\nimport android.content.Context;\r\nimport android.util.Log;\r\nimport com.webify.thunderbgservice.tasks.BackgroundTask;\r\nimport com.webify.thunderbgservice.tasks.TaskResultStorage;\r\nimport com.webify.thunderbgservice.tasks.TaskEventEmitter;\r\nimport org.json.JSONObject;\r\n\r\npublic class MySyncTask implements BackgroundTask {\r\n    private static final String TAG = \"MySyncTask\";\r\n    private int syncCount = 0;\r\n    \r\n    @Override\r\n    public void execute(Context context, String taskId) {\r\n        syncCount++;\r\n        Log.i(TAG, \"Sync #\" + syncCount);\r\n        \r\n        // 1. Stocker des données pour JS\r\n        TaskResultStorage.saveResult(context, taskId, \"syncCount\", String.valueOf(syncCount));\r\n        TaskResultStorage.saveResult(context, taskId, \"lastSync\", System.currentTimeMillis() + \"\");\r\n        \r\n        // 2. Émettre un événement (si l'app est active)\r\n        TaskEventEmitter.emit(context, taskId, \"Sync completed: \" + syncCount);\r\n        \r\n        // 3. Votre logique métier ici\r\n        performSync(context);\r\n    }\r\n    \r\n    @Override\r\n    public void onRegistered(Context context, String taskId) {\r\n        Log.i(TAG, \"Task registered: \" + taskId);\r\n        // Initialisation si nécessaire\r\n    }\r\n    \r\n    @Override\r\n    public void onUnregistered(Context context, String taskId) {\r\n        Log.i(TAG, \"Task unregistered: \" + taskId);\r\n        // Nettoyage si nécessaire\r\n    }\r\n    \r\n    private void performSync(Context context) {\r\n        // Votre code de synchronisation\r\n        // Ex: appeler une API, sauvegarder des données, etc.\r\n    }\r\n}\r\n```\r\n\r\n### 3. Enregistrer une tâche depuis TypeScript\r\n\r\n```typescript\r\nimport { ThunderBgService } from '@ahmed-mili/capacitor-thunder-bg-service';\r\n\r\n// Démarrer le service d'abord\r\nawait ThunderBgService.start({\r\n  notificationTitle: 'Online',\r\n  notificationSubtitle: 'Service actif',\r\n  enableLocation: true,\r\n});\r\n\r\n// Enregistrer une tâche\r\nawait ThunderBgService.registerTask({\r\n  taskId: 'syncTask',\r\n  taskClass: 'com.yourpackage.MySyncTask',  // Nom complet de la classe\r\n  intervalMs: 10000,  // Toutes les 10 secondes (minimum 1000ms)\r\n});\r\n```\r\n\r\n### 4. Écouter les événements de la tâche\r\n\r\n```typescript\r\n// Écouter les événements (seulement si l'app est active)\r\nThunderBgService.addListener('taskEvent', (data) => {\r\n  console.log('Événement de la tâche:', data.taskId);\r\n  console.log('Données:', data.data);\r\n  console.log('Timestamp:', data.timestamp);\r\n  \r\n  // Traiter les données\r\n  if (data.taskId === 'syncTask') {\r\n    handleSyncEvent(data.data);\r\n  }\r\n});\r\n```\r\n\r\n### 5. Récupérer les résultats stockés\r\n\r\n```typescript\r\n// Récupérer les résultats même si l'app était fermée\r\nasync function getTaskResults() {\r\n  const { result } = await ThunderBgService.getTaskResult('syncTask');\r\n  \r\n  if (result) {\r\n    console.log('Sync count:', result.syncCount);\r\n    console.log('Last sync:', result.lastSync);\r\n    console.log('Timestamp:', result.timestamp);\r\n  }\r\n}\r\n\r\n// Polling périodique\r\nsetInterval(async () => {\r\n  const { result } = await ThunderBgService.getTaskResult('syncTask');\r\n  if (result) {\r\n    updateUI(result);\r\n  }\r\n}, 5000);\r\n```\r\n\r\n### 6. Désenregistrer une tâche\r\n\r\n```typescript\r\n// Désenregistrer une tâche\r\nawait ThunderBgService.unregisterTask('syncTask');\r\n```\r\n\r\n### 7. Exemples de tâches\r\n\r\n#### Exemple 1: Vérification réseau\r\n\r\n```java\r\npublic class NetworkCheckTask implements BackgroundTask {\r\n    @Override\r\n    public void execute(Context context, String taskId) {\r\n        ConnectivityManager cm = (ConnectivityManager) \r\n            context.getSystemService(Context.CONNECTIVITY_SERVICE);\r\n        NetworkInfo info = cm.getActiveNetworkInfo();\r\n        boolean isConnected = info != null && info.isConnected();\r\n        \r\n        TaskResultStorage.saveResult(context, taskId, \"connected\", String.valueOf(isConnected));\r\n        \r\n        if (!isConnected) {\r\n            TaskEventEmitter.emit(context, taskId, \"Network disconnected\");\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n#### Exemple 2: Mise à jour de localisation\r\n\r\n```java\r\npublic class LocationUpdateTask implements BackgroundTask {\r\n    @Override\r\n    public void execute(Context context, String taskId) {\r\n        // Récupérer la localisation\r\n        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);\r\n        Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);\r\n        \r\n        if (location != null) {\r\n            JSONObject data = new JSONObject();\r\n            data.put(\"latitude\", location.getLatitude());\r\n            data.put(\"longitude\", location.getLongitude());\r\n            data.put(\"timestamp\", System.currentTimeMillis());\r\n            \r\n            TaskResultStorage.saveResult(context, taskId, data);\r\n            TaskEventEmitter.emit(context, taskId, data);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n#### Exemple 3: Synchronisation de données\r\n\r\n```java\r\npublic class DataSyncTask implements BackgroundTask {\r\n    @Override\r\n    public void execute(Context context, String taskId) {\r\n        try {\r\n            // Appeler votre API\r\n            String response = callApi(context);\r\n            \r\n            // Sauvegarder la réponse\r\n            TaskResultStorage.saveResult(context, taskId, \"lastResponse\", response);\r\n            TaskResultStorage.saveResult(context, taskId, \"syncStatus\", \"success\");\r\n            \r\n            TaskEventEmitter.emit(context, taskId, \"Sync successful\");\r\n        } catch (Exception e) {\r\n            TaskResultStorage.saveResult(context, taskId, \"syncStatus\", \"error\");\r\n            TaskResultStorage.saveResult(context, taskId, \"error\", e.getMessage());\r\n        }\r\n    }\r\n    \r\n    private String callApi(Context context) {\r\n        // Votre code HTTP ici\r\n        return \"\";\r\n    }\r\n}\r\n```\r\n\r\n---\r\n\r\n## 📍 Localisation\r\n\r\n### 1. Activation automatique\r\n\r\nLa localisation est activée automatiquement si `enableLocation: true` :\r\n\r\n```typescript\r\nawait ThunderBgService.start({\r\n  notificationTitle: 'Online',\r\n  notificationSubtitle: 'Service actif',\r\n  enableLocation: true,  // Active la localisation\r\n  customLayout: 'notification_online',  // REQUIS : layout personnalisé\r\n  titleViewId: 'txtTitle',\r\n  subtitleViewId: 'txtSubtitle',\r\n});\r\n```\r\n\r\n### 2. Utilisation dans une tâche\r\n\r\nVous pouvez accéder à la localisation depuis vos tâches :\r\n\r\n```java\r\npublic class LocationTask implements BackgroundTask {\r\n    @Override\r\n    public void execute(Context context, String taskId) {\r\n        FusedLocationProviderClient fused = \r\n            LocationServices.getFusedLocationProviderClient(context);\r\n        \r\n        fused.getLastLocation().addOnSuccessListener(location -> {\r\n            if (location != null) {\r\n                JSONObject data = new JSONObject();\r\n                data.put(\"lat\", location.getLatitude());\r\n                data.put(\"lng\", location.getLongitude());\r\n                TaskResultStorage.saveResult(context, taskId, data);\r\n            }\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n---\r\n\r\n## ☕ Utilisation depuis Java natif\r\n\r\n### 1. Import\r\n\r\n```java\r\nimport com.webify.thunderbgservice.core.ThunderBgServiceHelper;\r\n```\r\n\r\n### 2. Démarrer le service\r\n\r\n```java\r\n// Méthode simple\r\nThunderBgServiceHelper.startService(\r\n    context,\r\n    \"Online\",\r\n    \"En attente\",\r\n    true  // enableLocation\r\n);\r\n\r\n// Avec tous les paramètres\r\nThunderBgServiceHelper.startService(\r\n    context,\r\n    \"Online\",\r\n    \"En attente\",\r\n    true,  // enableLocation\r\n    false, // soundsEnabled\r\n    \"notification_custom\",  // customLayout\r\n    \"txtTitle\",            // titleViewId\r\n    \"txtSubtitle\",         // subtitleViewId\r\n    \"txtTimer\"             // timerViewId\r\n);\r\n```\r\n\r\n### 3. Mettre à jour la notification\r\n\r\n```java\r\n// Simple\r\nThunderBgServiceHelper.updateNotification(\r\n    context,\r\n    \"Nouveau titre\",\r\n    \"Nouveau sous-titre\"\r\n);\r\n\r\n// Avec changement de layout\r\nThunderBgServiceHelper.updateNotification(\r\n    context,\r\n    \"Titre\",\r\n    \"Sous-titre\",\r\n    \"notification_other\",  // customLayout\r\n    \"txtOtherTitle\",        // titleViewId\r\n    \"txtOtherSubtitle\",    // subtitleViewId\r\n    \"txtOtherTimer\"        // timerViewId\r\n);\r\n```\r\n\r\n### 4. Arrêter le service\r\n\r\n```java\r\nThunderBgServiceHelper.stopService(context);\r\n```\r\n\r\n### 5. Enregistrer une tâche\r\n\r\n```java\r\n// Avec une instance\r\nMyTask task = new MyTask();\r\nThunderBgServiceHelper.registerTask(context, \"myTask\", task, 5000);\r\n\r\n// Par nom de classe\r\nThunderBgServiceHelper.registerTask(\r\n    context,\r\n    \"myTask\",\r\n    \"com.yourpackage.MyTask\",\r\n    5000\r\n);\r\n```\r\n\r\n### 6. Désenregistrer une tâche\r\n\r\n```java\r\nThunderBgServiceHelper.unregisterTask(context, \"myTask\");\r\n```\r\n\r\n### 7. Vérifier si une tâche est enregistrée\r\n\r\n```java\r\nboolean isRegistered = ThunderBgServiceHelper.isTaskRegistered(\"myTask\");\r\n```\r\n\r\n### 8. Récupérer les résultats d'une tâche\r\n\r\n```java\r\nJSONObject result = ThunderBgServiceHelper.getTaskResult(context, \"myTask\");\r\nif (result != null) {\r\n    String data = result.getString(\"data\");\r\n}\r\n```\r\n\r\n### 9. Émettre un événement\r\n\r\n```java\r\nThunderBgServiceHelper.emitTaskEvent(context, \"myTask\", \"Données\");\r\n```\r\n\r\n### 10. Vérifier l'existence d'un layout\r\n\r\n```java\r\nboolean exists = ThunderBgServiceHelper.layoutExists(context, \"notification_custom\");\r\n```\r\n\r\n### 11. Exemple dans une Activity\r\n\r\n```java\r\npackage com.yourpackage;\r\n\r\nimport android.app.Activity;\r\nimport android.os.Bundle;\r\nimport android.widget.Button;\r\nimport com.webify.thunderbgservice.core.ThunderBgServiceHelper;\r\n\r\npublic class MainActivity extends Activity {\r\n    \r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        \r\n        Button startBtn = findViewById(R.id.btnStart);\r\n        startBtn.setOnClickListener(v -> {\r\n            ThunderBgServiceHelper.startService(\r\n                this,\r\n                \"Online\",\r\n                \"Service démarré\",\r\n                true\r\n            );\r\n        });\r\n        \r\n        Button stopBtn = findViewById(R.id.btnStop);\r\n        stopBtn.setOnClickListener(v -> {\r\n            ThunderBgServiceHelper.stopService(this);\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n---\r\n\r\n## 📚 API complète\r\n\r\n### TypeScript/JavaScript\r\n\r\n#### `start(options: StartOptions): Promise<{started: boolean}>`\r\n\r\nDémarre le service foreground.\r\n\r\n**Options:**\r\n- `notificationTitle?: string` - Titre de la notification (optionnel)\r\n- `notificationSubtitle?: string` - Sous-titre (optionnel)\r\n- `enableLocation?: boolean` - Activer la localisation (défaut: true)\r\n- `soundsEnabled?: boolean` - Activer les sons (défaut: false)\r\n- `customLayout?: string` - **Requis** : Nom du layout personnalisé (sans .xml)\r\n- `titleViewId?: string` - ID du TextView pour le titre\r\n- `subtitleViewId?: string` - ID du TextView pour le sous-titre\r\n- `timerViewId?: string` - ID du TextView pour le timer\r\n- `viewData?: { [viewIdName: string]: string }` - **Nouveau** : Objet pour injecter des textes dans n'importe quel TextView\r\n- `buttons?: Array<{ viewId: string; action: string; extras?: object }>` - **Nouveau** : Tableau de boutons cliquables\r\n\r\n#### `stop(): Promise<{stopped: boolean}>`\r\n\r\nArrête le service et toutes les tâches.\r\n\r\n#### `update(options: Partial<StartOptions>): Promise<{updated: boolean}>`\r\n\r\nMet à jour la notification. Tous les paramètres sont optionnels.\r\n\r\n#### `registerTask(options: RegisterTaskOptions): Promise<{registered: boolean}>`\r\n\r\nEnregistre une tâche en arrière-plan.\r\n\r\n**Options:**\r\n- `taskId: string` - ID unique de la tâche\r\n- `taskClass: string` - Nom complet de la classe Java\r\n- `intervalMs: number` - Intervalle en millisecondes (minimum 1000)\r\n\r\n#### `unregisterTask(taskId: string): Promise<{unregistered: boolean}>`\r\n\r\nDésenregistre une tâche.\r\n\r\n#### `getTaskResult(taskId: string): Promise<{result: any | null}>`\r\n\r\nRécupère les résultats stockés d'une tâche.\r\n\r\n#### `addListener(event: 'taskEvent', listener: Function): Promise<{remove: () => void}>`\r\n\r\nÉcoute les événements émis par les tâches.\r\n\r\n#### `removeAllListeners(): Promise<void>`\r\n\r\nSupprime tous les listeners.\r\n\r\n### Java natif\r\n\r\nVoir la section \"Utilisation depuis Java natif\" ci-dessus pour la liste complète des méthodes.\r\n\r\n---\r\n\r\n## 🏗️ Architecture\r\n\r\n### Structure du package\r\n\r\n```\r\ncom.webify.thunderbgservice/\r\n├── core/                    # Fichiers principaux\r\n│   ├── FgConstants.java     # Constantes\r\n│   ├── ForegroundTaskService.java  # Service Android\r\n│   ├── ThunderBgServicePlugin.java # Plugin Capacitor\r\n│   └── ThunderBgServiceHelper.java # Helper publique\r\n├── tasks/                   # Tâches en arrière-plan\r\n│   ├── BackgroundTask.java  # Interface\r\n│   ├── BackgroundTaskManager.java # Gestionnaire\r\n│   ├── TaskEventEmitter.java # Émission d'événements\r\n│   └── TaskResultStorage.java # Stockage de résultats\r\n└── helpers/                 # Utilitaires\r\n    ├── NotificationHelper.java # Gestion notifications\r\n    └── LocationHelper.java     # Gestion localisation\r\n```\r\n\r\n### Flux de données\r\n\r\n```\r\n┌─────────────┐\r\n│   App JS    │\r\n│  (TypeScript)│\r\n└──────┬──────┘\r\n       │\r\n       │ Capacitor Bridge\r\n       │\r\n┌──────▼──────────────────────┐\r\n│  ThunderBgServicePlugin     │\r\n│  (Capacitor Plugin)         │\r\n└──────┬──────────────────────┘\r\n       │\r\n       │ Intents\r\n       │\r\n┌──────▼──────────────────────┐\r\n│  ForegroundTaskService      │\r\n│  (Android Service)           │\r\n└──────┬──────────────────────┘\r\n       │\r\n       ├──► NotificationHelper\r\n       ├──► LocationHelper\r\n       └──► BackgroundTaskManager\r\n                │\r\n                └──► BackgroundTask (votre code)\r\n```\r\n\r\n---\r\n\r\n## 💡 Exemples\r\n\r\n### Exemple 1: Service de livraison\r\n\r\n```typescript\r\nclass DeliveryService {\r\n  async startDelivery() {\r\n    // Démarrer le service\r\n    await ThunderBgService.start({\r\n      notificationTitle: 'Livraison en cours',\r\n      notificationSubtitle: 'En route vers le client',\r\n      enableLocation: true,\r\n      customLayout: 'notification_delivery',\r\n      titleViewId: 'txtDeliveryStatus',\r\n      subtitleViewId: 'txtClientAddress',\r\n      timerViewId: 'txtElapsedTime',\r\n    });\r\n    \r\n    // Enregistrer une tâche de mise à jour de localisation\r\n    await ThunderBgService.registerTask({\r\n      taskId: 'locationUpdate',\r\n      taskClass: 'com.yourpackage.DeliveryLocationTask',\r\n      intervalMs: 5000,\r\n    });\r\n  }\r\n  \r\n  async updateDeliveryStatus(status: string, address: string) {\r\n    await ThunderBgService.update({\r\n      notificationTitle: status,\r\n      notificationSubtitle: address,\r\n    });\r\n  }\r\n  \r\n  async stopDelivery() {\r\n    await ThunderBgService.unregisterTask('locationUpdate');\r\n    await ThunderBgService.stop();\r\n  }\r\n}\r\n```\r\n\r\n### Exemple 2: Application de fitness\r\n\r\n```typescript\r\nclass FitnessTracker {\r\n  async startWorkout() {\r\n    await ThunderBgService.start({\r\n      notificationTitle: 'Entraînement en cours',\r\n      notificationSubtitle: 'Course',\r\n      enableLocation: true,\r\n      customLayout: 'notification_workout',\r\n      titleViewId: 'txtWorkoutType',\r\n      subtitleViewId: 'txtDistance',\r\n      timerViewId: 'txtDuration',\r\n    });\r\n    \r\n    // Enregistrer une tâche de tracking\r\n    await ThunderBgService.registerTask({\r\n      taskId: 'fitnessTracking',\r\n      taskClass: 'com.yourpackage.FitnessTrackingTask',\r\n      intervalMs: 2000,\r\n    });\r\n  }\r\n  \r\n  async updateWorkoutData(distance: string) {\r\n    await ThunderBgService.update({\r\n      notificationSubtitle: `Distance: ${distance} km`,\r\n    });\r\n  }\r\n}\r\n```\r\n\r\n### Exemple 3: Application de monitoring\r\n\r\n```typescript\r\nclass MonitoringService {\r\n  async startMonitoring() {\r\n    await ThunderBgService.start({\r\n      notificationTitle: 'Monitoring actif',\r\n      notificationSubtitle: 'Surveillance en cours',\r\n      enableLocation: false,\r\n    });\r\n    \r\n    // Tâche de vérification système\r\n    await ThunderBgService.registerTask({\r\n      taskId: 'systemCheck',\r\n      taskClass: 'com.yourpackage.SystemCheckTask',\r\n      intervalMs: 30000,\r\n    });\r\n    \r\n    // Écouter les événements\r\n    ThunderBgService.addListener('taskEvent', (data) => {\r\n      if (data.taskId === 'systemCheck') {\r\n        this.handleSystemAlert(data.data);\r\n      }\r\n    });\r\n  }\r\n  \r\n  private handleSystemAlert(data: any) {\r\n    // Traiter les alertes système\r\n    console.log('Alert:', data);\r\n  }\r\n  \r\n  async getSystemStatus() {\r\n    const { result } = await ThunderBgService.getTaskResult('systemCheck');\r\n    return result;\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🔧 Dépannage\r\n\r\n### Le service s'arrête quand l'app est fermée\r\n\r\n✅ **Solution**: Le service est conçu pour persister. Vérifiez :\r\n- Les permissions sont accordées\r\n- Le service est bien démarré avec `start()`\r\n- Aucune restriction de batterie n'est active\r\n\r\n### La notification ne s'affiche pas\r\n\r\n✅ **Solution**:\r\n1. Vérifiez que la permission `POST_NOTIFICATIONS` est accordée (Android 13+)\r\n2. Vérifiez que le canal de notification existe\r\n3. Vérifiez que le service est bien démarré\r\n\r\n### Les tâches ne s'exécutent pas\r\n\r\n✅ **Solution**:\r\n1. Vérifiez que le service est démarré avant d'enregistrer les tâches\r\n2. Vérifiez que la classe Java existe et implémente `BackgroundTask`\r\n3. Vérifiez les logs Android (logcat) pour les erreurs\r\n\r\n### Les événements ne sont pas reçus\r\n\r\n✅ **Solution**:\r\n- Les événements ne sont émis que si l'app est active\r\n- Utilisez `getTaskResult()` pour récupérer les données si l'app était fermée\r\n- Vérifiez que le listener est bien enregistré\r\n\r\n### Le layout personnalisé ne s'affiche pas\r\n\r\n✅ **Solution**:\r\n1. Vérifiez que le fichier XML existe dans `res/layout/`\r\n2. Vérifiez que les IDs des TextViews sont corrects\r\n3. Vérifiez les logs pour voir les IDs résolus\r\n4. **Important** : Le plugin ne contient pas de layout par défaut. Vous devez toujours fournir `customLayout`\r\n\r\n### Les boutons dans la notification ne fonctionnent pas\r\n\r\n✅ **Solution**:\r\n1. Vérifiez que le `BroadcastReceiver` est déclaré dans `AndroidManifest.xml` avec `android:exported=\"true\"`\r\n2. Vérifiez que les actions dans `buttons` correspondent exactement aux actions déclarées dans le Receiver\r\n3. Vérifiez que les IDs de boutons dans `buttons` correspondent exactement aux IDs dans votre XML (sans `@+id/`)\r\n4. Utilisez `Button` ou `TextView` avec `android:clickable=\"true\"` dans votre layout\r\n5. Vérifiez les logs Logcat (filtre `ThunderBG`) pour voir si les boutons sont bindés : cherchez `\"Button bound: viewId=...\"` ou `\"⚠️ NO RECEIVER FOUND\"`\r\n6. Vérifiez les logs de votre Receiver pour voir si les intents sont reçus : ajoutez `Log.d(\"Receiver\", \"Received: \" + intent.getAction())`\r\n\r\n### Erreur de compilation Java\r\n\r\n✅ **Solution**:\r\n- Vérifiez que tous les imports sont corrects\r\n- Utilisez `com.webify.thunderbgservice.core.*` pour les classes core\r\n- Utilisez `com.webify.thunderbgservice.tasks.*` pour les tâches\r\n\r\n---\r\n\r\n## 📖 Ressources supplémentaires\r\n\r\n### Documentation\r\n- [📘 Guide de démarrage rapide](./docs/QUICK_START.md) - Commencez en 5 minutes\r\n- [📚 Référence API complète](./docs/API_REFERENCE.md) - Toutes les méthodes détaillées\r\n- [💡 Cas d'usage pratiques](./docs/USE_CASES.md) - Exemples réels d'utilisation\r\n- [🏗️ Architecture et organisation](./docs/ORGANIZATION.md) - Structure du package\r\n\r\n### Exemples\r\n- [📁 Index des exemples](./examples/INDEX.md) - Guide de navigation\r\n- [📝 Exemples TypeScript/JavaScript](./examples/EXAMPLE_usage.ts)\r\n- [☕ Exemples Java natif](./examples/EXAMPLE_NativeJavaUsage.java)\r\n- [🔄 Tâches en arrière-plan](./examples/EXAMPLE_BackgroundTask_usage.ts)\r\n- [📡 Communication JS/Java](./examples/EXAMPLE_TaskJSCommunication.ts)\r\n\r\n### Guides\r\n- [🎯 Guide des tâches](./examples/EXAMPLE_BackgroundTasks_README.md)\r\n- [🔌 Guide d'utilisation native](./examples/EXAMPLE_NativeUsage_README.md)\r\n- [💬 Guide de communication JS/TS](./examples/EXAMPLE_TS_JS_Tasks_README.md)\r\n\r\n---\r\n\r\n## 📝 Notes importantes\r\n\r\n1. **UI 100% app-driven**: Le plugin ne contient aucune UI/logique par défaut. Vous devez fournir `customLayout`, `viewData` et `buttons` depuis votre app.\r\n2. **Layout requis**: Vous devez toujours fournir `customLayout` lors du démarrage. Créez vos layouts dans `res/layout/` de votre app.\r\n3. **Persistance automatique**: L'UI et l'état (layout, viewData, buttons) sont automatiquement sauvegardés et restaurés après fermeture/réouverture de l'app.\r\n4. **Batterie**: Les intervalles courts peuvent drainer la batterie. Utilisez des intervalles >= 5000ms pour les tâches.\r\n5. **Permissions**: Toujours demander les permissions runtime avant d'utiliser le service.\r\n6. **Tâches**: Les tâches doivent être en Java natif, pas en JavaScript.\r\n7. **Boutons cliquables**: Utilisez `Button` ou `TextView` avec `android:clickable=\"true\"` dans vos layouts. Déclarez le `BroadcastReceiver` avec `android:exported=\"true\"` dans le Manifest.\r\n\r\n---\r\n\r\n## 🆘 Support\r\n\r\nPour toute question ou problème, consultez les exemples dans le dossier `examples/` ou ouvrez une issue sur le repository.\r\n\r\n---\r\n\r\n**Version**: 0.1.0  \r\n**Capacitor**: ^7.0.0  \r\n**Android**: API 21+\r\n\r\n","readmeFilename":"README.md"}