[{"data":1,"prerenderedAt":1102},["ShallowReactive",2],{"blog-\u002Fblog\u002Fapplication-mobile-pwa-native-tauri":3,"blog-related-\u002Fblog\u002Fapplication-mobile-pwa-native-tauri":1083},{"id":4,"title":5,"body":6,"category":1066,"date":1067,"description":1068,"draft":1069,"extension":1070,"meta":1071,"navigation":396,"path":1072,"readingTime":370,"seo":1073,"sitemap":1074,"stem":1075,"tags":1076,"__hash__":1082},"blog\u002Fblog\u002Fapplication-mobile-pwa-native-tauri.md","Application mobile : native, Flutter, PWA ou Tauri 2, comment choisir ?",{"type":7,"value":8,"toc":1046},"minimark",[9,13,18,23,26,29,33,36,39,43,46,49,53,56,59,63,67,70,74,77,81,84,88,91,95,98,102,254,258,261,751,754,863,940,943,997,1001,1004,1008,1011,1027,1030,1034,1042],[10,11,12],"p",{},"Choisir la technologie d'une application mobile engage l'équipe pour plusieurs années. Un mauvais choix se paie en coûts de maintenance, en fonctionnalités impossibles à livrer ou en refus de publication sur les stores. Nous accompagnons régulièrement des organisations sur cette question, et la réponse dépend moins des modes que de quelques critères très concrets : ce que l'application doit faire avec le matériel, si elle doit fonctionner sans réseau, et qui la maintiendra demain. Voici notre grille de lecture, avec les quatre grandes familles d'approches.",[14,15,17],"h2",{"id":16},"les-quatre-familles-dapproches","Les quatre familles d'approches",[19,20,22],"h3",{"id":21},"le-natif-swift-et-kotlin","Le natif : Swift et Kotlin",[10,24,25],{},"Le développement natif consiste à écrire deux applications distinctes : Swift (ou SwiftUI) pour iOS, Kotlin (et Jetpack Compose) pour Android. C'est la voie qui offre le meilleur accès aux API de la plateforme dès leur sortie, les meilleures performances graphiques et l'intégration la plus fidèle aux conventions de chaque système.",[10,27,28],{},"Le prix à payer est double : deux bases de code, donc deux équipes ou des profils rares, et un coût de maintenance qui se multiplie à chaque évolution fonctionnelle. Le natif se justifie pour les applications très gourmandes en calcul graphique, en réalité augmentée ou fortement liées à des API récentes du système.",[19,30,32],{"id":31},"le-cross-platform-flutter-et-react-native","Le cross-platform : Flutter et React Native",[10,34,35],{},"Flutter (Dart) dessine sa propre interface avec son moteur de rendu. React Native (TypeScript) pilote des composants natifs depuis du JavaScript. Dans les deux cas, une seule base de code vise iOS et Android, avec un accès au matériel via des plugins maintenus par l'écosystème.",[10,37,38],{},"C'est un excellent compromis pour une application mobile « pure ». Les limites apparaissent quand il faut aussi un site web ou une application de bureau : l'interface mobile ne se réutilise pas directement, et il faut souvent maintenir une seconde application web à côté.",[19,40,42],{"id":41},"la-pwa-le-web-installable","La PWA : le web installable",[10,44,45],{},"Une Progressive Web App est un site web enrichi d'un manifeste, d'un service worker et d'une mise en cache. Elle s'installe sur l'écran d'accueil, fonctionne hors-ligne dans une certaine mesure et se déploie comme n'importe quel site : pas de validation par un store, mise à jour instantanée.",[10,47,48],{},"Ses limites sont connues. L'accès au matériel dépend du navigateur : la caméra et la géolocalisation fonctionnent bien, le Bluetooth ou le NFC restent inégaux, notamment sur iOS. La présence sur les stores n'est pas native, et le comportement du stockage hors-ligne varie selon les navigateurs. Pour un outil interne ou un service de consultation, c'est souvent largement suffisant.",[19,50,52],{"id":51},"tauri-2-une-base-web-un-cœur-en-rust","Tauri 2 : une base web, un cœur en Rust",[10,54,55],{},"Tauri 2 permet de réutiliser une application web (Vue, Nuxt, React ou autre) et de l'empaqueter dans une application native, avec un cœur en Rust. Une même base de code cible le web, le bureau (Windows, macOS, Linux), Android et iOS. L'interface est rendue par la WebView du système, ce qui donne des binaires légers, et les fonctions natives sont exposées par des plugins officiels (scanner de codes-barres, NFC, notifications, système de fichiers, etc.).",[10,57,58],{},"Pour une équipe qui maîtrise déjà Vue et Nuxt, c'est un levier considérable : les composants, les stores et les routes sont partagés entre le site, l'application mobile et la version bureau. Le code Rust n'intervient que lorsqu'un besoin spécifique l'exige.",[14,60,62],{"id":61},"les-critères-qui-comptent-vraiment","Les critères qui comptent vraiment",[19,64,66],{"id":65},"accès-matériel","Accès matériel",[10,68,69],{},"Pour un scanner de codes-barres, de la NFC ou une caméra pilotée finement, le natif et les solutions cross-platform sont à l'aise. Tauri 2 couvre ces besoins via ses plugins officiels, et permet d'écrire ses propres commandes en Rust quand un plugin n'existe pas. La PWA reste la plus limitée, surtout sur iOS.",[19,71,73],{"id":72},"hors-ligne","Hors-ligne",[10,75,76],{},"Un usage en magasin, en entrepôt ou en zone mal couverte impose de penser la synchronisation dès le départ. Une base locale (SQLite, IndexedDB), une file d'opérations en attente et une stratégie de résolution de conflits comptent plus que le choix du framework. Une application empaquetée avec Tauri garde ses ressources sur l'appareil, ce qui simplifie le démarrage sans réseau par rapport à une PWA dépendante de son cache.",[19,78,80],{"id":79},"performance","Performance",[10,82,83],{},"Le natif et Flutter gagnent sur les animations complexes et les interfaces très riches. Une application de gestion, composée de listes, de formulaires et de scans, tourne parfaitement dans une WebView moderne. La performance perçue dépend davantage de la qualité de l'interface et des appels réseau que du moteur de rendu.",[19,85,87],{"id":86},"maintenance-et-mises-à-jour","Maintenance et mises à jour",[10,89,90],{},"Moins il y a de bases de code, moins il y a de dette. Sur ce point, Tauri et la PWA partent avec un avantage quand une équipe web existe déjà. Côté mises à jour, la PWA est imbattable (un déploiement suffit). Pour les applications publiées sur les stores, chaque version repasse par une validation, ce qui impose de prévoir des délais et de découpler le plus possible la logique métier côté serveur.",[19,92,94],{"id":93},"publication-sur-les-stores","Publication sur les stores",[10,96,97],{},"Publier sur l'App Store et Google Play suppose des comptes développeur, des certificats, des captures d'écran, une politique de confidentialité et le respect des règles de chaque store. C'est vrai quelle que soit la technologie. Le natif, Flutter, React Native et Tauri produisent tous des binaires acceptés. La PWA, elle, ne passe pas par ce circuit sans enveloppe supplémentaire.",[14,99,101],{"id":100},"tableau-comparatif","Tableau comparatif",[103,104,105,127],"table",{},[106,107,108],"thead",{},[109,110,111,115,118,121,124],"tr",{},[112,113,114],"th",{},"Critère",[112,116,117],{},"Natif (Swift\u002FKotlin)",[112,119,120],{},"Flutter \u002F React Native",[112,122,123],{},"PWA",[112,125,126],{},"Tauri 2",[128,129,130,148,164,177,192,208,222,238],"tbody",{},[109,131,132,136,139,142,145],{},[133,134,135],"td",{},"Bases de code",[133,137,138],{},"2",[133,140,141],{},"1 (mobile)",[133,143,144],{},"1",[133,146,147],{},"1 (web, bureau, mobile)",[109,149,150,152,155,158,161],{},[133,151,66],{},[133,153,154],{},"Complet",[133,156,157],{},"Très bon (plugins)",[133,159,160],{},"Limité, variable",[133,162,163],{},"Bon (plugins, Rust)",[109,165,166,168,170,172,175],{},[133,167,73],{},[133,169,154],{},[133,171,154],{},[133,173,174],{},"Partiel",[133,176,154],{},[109,178,179,181,184,187,190],{},[133,180,80],{},[133,182,183],{},"Excellente",[133,185,186],{},"Très bonne",[133,188,189],{},"Bonne",[133,191,189],{},[109,193,194,197,200,203,206],{},[133,195,196],{},"Réutilisation d'une équipe web",[133,198,199],{},"Faible",[133,201,202],{},"Moyenne",[133,204,205],{},"Forte",[133,207,205],{},[109,209,210,212,215,217,220],{},[133,211,94],{},[133,213,214],{},"Oui",[133,216,214],{},[133,218,219],{},"Non native",[133,221,214],{},[109,223,224,227,230,232,235],{},[133,225,226],{},"Mises à jour",[133,228,229],{},"Via les stores",[133,231,229],{},[133,233,234],{},"Instantanées",[133,236,237],{},"Via les stores (et web)",[109,239,240,243,246,249,251],{},[133,241,242],{},"Coût de maintenance",[133,244,245],{},"Élevé",[133,247,248],{},"Moyen",[133,250,199],{},[133,252,253],{},"Faible à moyen",[14,255,257],{"id":256},"un-exemple-avec-tauri-2-et-vue","Un exemple avec Tauri 2 et Vue",[10,259,260],{},"Côté Vue, l'appel d'un plugin natif se fait avec quelques lignes de TypeScript. Voici un composant qui lance un scan de code-barres après avoir demandé l'autorisation d'utiliser la caméra :",[262,263,268],"pre",{"className":264,"code":265,"language":266,"meta":267,"style":267},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","\u003Cscript setup lang=\"ts\">\nimport { ref } from 'vue'\nimport {\n  Format,\n  checkPermissions,\n  requestPermissions,\n  scan,\n} from '@tauri-apps\u002Fplugin-barcode-scanner'\n\nconst code = ref\u003Cstring | null>(null)\n\nasync function scanProduct() {\n  let state = await checkPermissions()\n  if (state !== 'granted') {\n    state = await requestPermissions()\n  }\n  if (state !== 'granted') return\n\n  const result = await scan({ formats: [Format.EAN13], windowed: false })\n  code.value = result.content\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton type=\"button\" @click=\"scanProduct\">Scanner un produit\u003C\u002Fbutton>\n  \u003Cp v-if=\"code\">Code lu : {{ code }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n","vue","",[269,270,271,307,335,343,352,360,368,376,391,398,441,446,463,484,513,528,534,556,561,619,639,645,655,660,670,713,742],"code",{"__ignoreMap":267},[272,273,276,280,284,288,291,294,298,302,304],"span",{"class":274,"line":275},"line",1,[272,277,279],{"class":278},"sP7_E","\u003C",[272,281,283],{"class":282},"sQzsp","script",[272,285,287],{"class":286},"s9AJx"," setup",[272,289,290],{"class":286}," lang",[272,292,293],{"class":278},"=",[272,295,297],{"class":296},"sjJ54","\"",[272,299,301],{"class":300},"s_sjI","ts",[272,303,297],{"class":296},[272,305,306],{"class":278},">\n",[272,308,310,314,317,321,324,327,330,332],{"class":274,"line":309},2,[272,311,313],{"class":312},"sVHd0","import",[272,315,316],{"class":278}," {",[272,318,320],{"class":319},"su5hD"," ref",[272,322,323],{"class":278}," }",[272,325,326],{"class":312}," from",[272,328,329],{"class":296}," '",[272,331,266],{"class":300},[272,333,334],{"class":296},"'\n",[272,336,338,340],{"class":274,"line":337},3,[272,339,313],{"class":312},[272,341,342],{"class":278}," {\n",[272,344,346,349],{"class":274,"line":345},4,[272,347,348],{"class":319},"  Format",[272,350,351],{"class":278},",\n",[272,353,355,358],{"class":274,"line":354},5,[272,356,357],{"class":319},"  checkPermissions",[272,359,351],{"class":278},[272,361,363,366],{"class":274,"line":362},6,[272,364,365],{"class":319},"  requestPermissions",[272,367,351],{"class":278},[272,369,371,374],{"class":274,"line":370},7,[272,372,373],{"class":319},"  scan",[272,375,351],{"class":278},[272,377,379,382,384,386,389],{"class":274,"line":378},8,[272,380,381],{"class":278},"}",[272,383,326],{"class":312},[272,385,329],{"class":296},[272,387,388],{"class":300},"@tauri-apps\u002Fplugin-barcode-scanner",[272,390,334],{"class":296},[272,392,394],{"class":274,"line":393},9,[272,395,397],{"emptyLinePlaceholder":396},true,"\n",[272,399,401,405,409,413,416,418,422,425,428,431,434,438],{"class":274,"line":400},10,[272,402,404],{"class":403},"sbsja","const",[272,406,408],{"class":407},"s_hVV"," code",[272,410,412],{"class":411},"smGrS"," =",[272,414,320],{"class":415},"sGLFI",[272,417,279],{"class":278},[272,419,421],{"class":420},"sZMiF","string",[272,423,424],{"class":411}," |",[272,426,427],{"class":420}," null",[272,429,430],{"class":278},">",[272,432,433],{"class":319},"(",[272,435,437],{"class":436},"s39Yj","null",[272,439,440],{"class":319},")\n",[272,442,444],{"class":274,"line":443},11,[272,445,397],{"emptyLinePlaceholder":396},[272,447,449,452,455,458,461],{"class":274,"line":448},12,[272,450,451],{"class":403},"async",[272,453,454],{"class":403}," function",[272,456,457],{"class":415}," scanProduct",[272,459,460],{"class":278},"()",[272,462,342],{"class":278},[272,464,466,469,472,474,477,480],{"class":274,"line":465},13,[272,467,468],{"class":403},"  let",[272,470,471],{"class":319}," state",[272,473,412],{"class":411},[272,475,476],{"class":312}," await",[272,478,479],{"class":415}," checkPermissions",[272,481,483],{"class":482},"skxfh","()\n",[272,485,487,490,493,496,499,501,504,507,510],{"class":274,"line":486},14,[272,488,489],{"class":312},"  if",[272,491,492],{"class":482}," (",[272,494,495],{"class":319},"state",[272,497,498],{"class":411}," !==",[272,500,329],{"class":296},[272,502,503],{"class":300},"granted",[272,505,506],{"class":296},"'",[272,508,509],{"class":482},") ",[272,511,512],{"class":278},"{\n",[272,514,516,519,521,523,526],{"class":274,"line":515},15,[272,517,518],{"class":319},"    state",[272,520,412],{"class":411},[272,522,476],{"class":312},[272,524,525],{"class":415}," requestPermissions",[272,527,483],{"class":482},[272,529,531],{"class":274,"line":530},16,[272,532,533],{"class":278},"  }\n",[272,535,537,539,541,543,545,547,549,551,553],{"class":274,"line":536},17,[272,538,489],{"class":312},[272,540,492],{"class":482},[272,542,495],{"class":319},[272,544,498],{"class":411},[272,546,329],{"class":296},[272,548,503],{"class":300},[272,550,506],{"class":296},[272,552,509],{"class":482},[272,554,555],{"class":312},"return\n",[272,557,559],{"class":274,"line":558},18,[272,560,397],{"emptyLinePlaceholder":396},[272,562,564,567,570,572,574,577,579,582,585,588,591,594,597,600,603,606,609,611,615,617],{"class":274,"line":563},19,[272,565,566],{"class":403},"  const",[272,568,569],{"class":407}," result",[272,571,412],{"class":411},[272,573,476],{"class":312},[272,575,576],{"class":415}," scan",[272,578,433],{"class":482},[272,580,581],{"class":278},"{",[272,583,584],{"class":482}," formats",[272,586,587],{"class":278},":",[272,589,590],{"class":482}," [",[272,592,593],{"class":319},"Format",[272,595,596],{"class":278},".",[272,598,599],{"class":407},"EAN13",[272,601,602],{"class":482},"]",[272,604,605],{"class":278},",",[272,607,608],{"class":482}," windowed",[272,610,587],{"class":278},[272,612,614],{"class":613},"syTEX"," false",[272,616,323],{"class":278},[272,618,440],{"class":482},[272,620,622,625,627,630,632,634,636],{"class":274,"line":621},20,[272,623,624],{"class":319},"  code",[272,626,596],{"class":278},[272,628,629],{"class":319},"value",[272,631,412],{"class":411},[272,633,569],{"class":319},[272,635,596],{"class":278},[272,637,638],{"class":319},"content\n",[272,640,642],{"class":274,"line":641},21,[272,643,644],{"class":278},"}\n",[272,646,648,651,653],{"class":274,"line":647},22,[272,649,650],{"class":278},"\u003C\u002F",[272,652,283],{"class":282},[272,654,306],{"class":278},[272,656,658],{"class":274,"line":657},23,[272,659,397],{"emptyLinePlaceholder":396},[272,661,663,665,668],{"class":274,"line":662},24,[272,664,279],{"class":278},[272,666,667],{"class":282},"template",[272,669,306],{"class":278},[272,671,673,676,679,682,684,686,688,690,693,695,697,700,702,704,707,709,711],{"class":274,"line":672},25,[272,674,675],{"class":278},"  \u003C",[272,677,678],{"class":282},"button",[272,680,681],{"class":286}," type",[272,683,293],{"class":278},[272,685,297],{"class":296},[272,687,678],{"class":300},[272,689,297],{"class":296},[272,691,692],{"class":286}," @click",[272,694,293],{"class":278},[272,696,297],{"class":296},[272,698,699],{"class":300},"scanProduct",[272,701,297],{"class":296},[272,703,430],{"class":278},[272,705,706],{"class":319},"Scanner un produit",[272,708,650],{"class":278},[272,710,678],{"class":282},[272,712,306],{"class":278},[272,714,716,718,720,723,725,727,729,731,733,736,738,740],{"class":274,"line":715},26,[272,717,675],{"class":278},[272,719,10],{"class":282},[272,721,722],{"class":286}," v-if",[272,724,293],{"class":278},[272,726,297],{"class":296},[272,728,269],{"class":300},[272,730,297],{"class":296},[272,732,430],{"class":278},[272,734,735],{"class":319},"Code lu : {{ code }}",[272,737,650],{"class":278},[272,739,10],{"class":282},[272,741,306],{"class":278},[272,743,745,747,749],{"class":274,"line":744},27,[272,746,650],{"class":278},[272,748,667],{"class":282},[272,750,306],{"class":278},[10,752,753],{},"Et pour une logique spécifique, une commande Rust s'expose en quelques lignes, puis s'appelle depuis le front :",[262,755,759],{"className":756,"code":757,"language":758,"meta":267,"style":267},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark","#[tauri::command]\nfn normalize_ean(code: String) -> String {\n    code.trim().chars().filter(|c| c.is_ascii_digit()).collect()\n}\n","rust",[269,760,761,778,807,859],{"__ignoreMap":267},[272,762,763,766,769,772,775],{"class":274,"line":275},[272,764,765],{"class":278},"#[",[272,767,768],{"class":319},"tauri",[272,770,771],{"class":411},"::",[272,773,774],{"class":319},"command",[272,776,777],{"class":278},"]\n",[272,779,780,784,787,789,791,793,797,800,803,805],{"class":274,"line":309},[272,781,783],{"class":782},"sw1J6","fn",[272,785,786],{"class":415}," normalize_ean",[272,788,433],{"class":278},[272,790,269],{"class":319},[272,792,587],{"class":411},[272,794,796],{"class":795},"sbgvK"," String",[272,798,799],{"class":278},")",[272,801,802],{"class":411}," ->",[272,804,796],{"class":795},[272,806,342],{"class":278},[272,808,809,812,814,817,819,821,824,826,828,831,833,836,839,841,844,846,849,852,854,857],{"class":274,"line":337},[272,810,811],{"class":319},"    code",[272,813,596],{"class":411},[272,815,816],{"class":415},"trim",[272,818,460],{"class":278},[272,820,596],{"class":411},[272,822,823],{"class":415},"chars",[272,825,460],{"class":278},[272,827,596],{"class":411},[272,829,830],{"class":415},"filter",[272,832,433],{"class":278},[272,834,835],{"class":411},"|",[272,837,838],{"class":319},"c",[272,840,835],{"class":411},[272,842,843],{"class":319}," c",[272,845,596],{"class":411},[272,847,848],{"class":415},"is_ascii_digit",[272,850,851],{"class":278},"())",[272,853,596],{"class":411},[272,855,856],{"class":415},"collect",[272,858,483],{"class":278},[272,860,861],{"class":274,"line":345},[272,862,644],{"class":278},[262,864,867],{"className":865,"code":866,"language":301,"meta":267,"style":267},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","import { invoke } from '@tauri-apps\u002Fapi\u002Fcore'\n\nconst ean = await invoke\u003Cstring>('normalize_ean', { code: ' 3017 6200 00000 ' })\n",[269,868,869,889,893],{"__ignoreMap":267},[272,870,871,873,875,878,880,882,884,887],{"class":274,"line":275},[272,872,313],{"class":312},[272,874,316],{"class":278},[272,876,877],{"class":319}," invoke",[272,879,323],{"class":278},[272,881,326],{"class":312},[272,883,329],{"class":296},[272,885,886],{"class":300},"@tauri-apps\u002Fapi\u002Fcore",[272,888,334],{"class":296},[272,890,891],{"class":274,"line":309},[272,892,397],{"emptyLinePlaceholder":396},[272,894,895,897,900,902,904,906,908,910,912,914,916,919,921,923,925,927,929,931,934,936,938],{"class":274,"line":337},[272,896,404],{"class":403},[272,898,899],{"class":407}," ean",[272,901,412],{"class":411},[272,903,476],{"class":312},[272,905,877],{"class":415},[272,907,279],{"class":278},[272,909,421],{"class":420},[272,911,430],{"class":278},[272,913,433],{"class":319},[272,915,506],{"class":296},[272,917,918],{"class":300},"normalize_ean",[272,920,506],{"class":296},[272,922,605],{"class":278},[272,924,316],{"class":278},[272,926,408],{"class":482},[272,928,587],{"class":278},[272,930,329],{"class":296},[272,932,933],{"class":300}," 3017 6200 00000 ",[272,935,506],{"class":296},[272,937,323],{"class":278},[272,939,440],{"class":319},[10,941,942],{},"Le cycle de développement mobile reste dans la ligne de commande :",[262,944,948],{"className":945,"code":946,"language":947,"meta":267,"style":267},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","pnpm tauri android init\npnpm tauri ios init\npnpm tauri ios dev\npnpm tauri ios build\n","bash",[269,949,950,964,975,986],{"__ignoreMap":267},[272,951,952,955,958,961],{"class":274,"line":275},[272,953,954],{"class":795},"pnpm",[272,956,957],{"class":300}," tauri",[272,959,960],{"class":300}," android",[272,962,963],{"class":300}," init\n",[272,965,966,968,970,973],{"class":274,"line":309},[272,967,954],{"class":795},[272,969,957],{"class":300},[272,971,972],{"class":300}," ios",[272,974,963],{"class":300},[272,976,977,979,981,983],{"class":274,"line":337},[272,978,954],{"class":795},[272,980,957],{"class":300},[272,982,972],{"class":300},[272,984,985],{"class":300}," dev\n",[272,987,988,990,992,994],{"class":274,"line":345},[272,989,954],{"class":795},[272,991,957],{"class":300},[272,993,972],{"class":300},[272,995,996],{"class":300}," build\n",[14,998,1000],{"id":999},"notre-retour-dexpérience","Notre retour d'expérience",[10,1002,1003],{},"Nous avons livré en production une application de gestion des dates de péremption destinée à la grande distribution, construite avec Nuxt, Tauri et Supabase, et disponible sur l'App Store. Ce projet nous a confirmé plusieurs points : une base Vue\u002FNuxt partagée accélère nettement les livraisons, le scan de codes-barres via plugin est fiable dès lors qu'on soigne les permissions et l'ergonomie, et le hors-ligne se conçoit en amont, pas en rattrapage. Il nous a aussi rappelé que la publication sur le store est un chantier à part entière, à anticiper dans le calendrier.",[14,1005,1007],{"id":1006},"comment-trancher","Comment trancher",[10,1009,1010],{},"Quelques repères simples résument notre approche :",[1012,1013,1014,1018,1021,1024],"ul",{},[1015,1016,1017],"li",{},"Un outil de consultation ou un service sans besoin matériel avancé : une PWA suffit souvent.",[1015,1019,1020],{},"Une application métier avec scan, hors-ligne et présence sur les stores, portée par une équipe web : Tauri 2 est un très bon candidat.",[1015,1022,1023],{},"Une application grand public, très visuelle, sans site web associé : Flutter ou React Native.",[1015,1025,1026],{},"Des exigences de performance graphique ou d'intégration profonde au système : le natif.",[10,1028,1029],{},"Dans tous les cas, mieux vaut valider le risque principal par un prototype court (le scan, la synchronisation, le passage en production sur le store) avant d'engager le projet complet.",[14,1031,1033],{"id":1032},"besoin-dun-coup-de-main","Besoin d'un coup de main ?",[10,1035,1036,1037,596],{},"Vous hésitez entre plusieurs approches ou vous souhaitez valider la faisabilité d'une application mobile ? Nous pouvons réaliser avec vous un cadrage technique et un prototype ciblé. N'hésitez pas à ",[1038,1039,1041],"a",{"href":1040},"\u002F#contact","nous contacter",[1043,1044,1045],"style",{},"html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":267,"searchDepth":309,"depth":309,"links":1047},[1048,1054,1061,1062,1063,1064,1065],{"id":16,"depth":309,"text":17,"children":1049},[1050,1051,1052,1053],{"id":21,"depth":337,"text":22},{"id":31,"depth":337,"text":32},{"id":41,"depth":337,"text":42},{"id":51,"depth":337,"text":52},{"id":61,"depth":309,"text":62,"children":1055},[1056,1057,1058,1059,1060],{"id":65,"depth":337,"text":66},{"id":72,"depth":337,"text":73},{"id":79,"depth":337,"text":80},{"id":86,"depth":337,"text":87},{"id":93,"depth":337,"text":94},{"id":100,"depth":309,"text":101},{"id":256,"depth":309,"text":257},{"id":999,"depth":309,"text":1000},{"id":1006,"depth":309,"text":1007},{"id":1032,"depth":309,"text":1033},"Mobile","2026-10-06","Native, cross-platform, PWA ou Tauri 2 : comparatif concret selon l'accès matériel, le hors-ligne, la maintenance et la publication sur les stores.",false,"md",{},"\u002Fblog\u002Fapplication-mobile-pwa-native-tauri",{"title":5,"description":1068},{"loc":1072,"lastmod":1067},"blog\u002Fapplication-mobile-pwa-native-tauri",[1077,768,1078,1079,1080,1081],"mobile","ios","android","pwa","nuxt","vxa4bPBQb9yrF1YUWBxAQfhIWTaxFDGyFyBDWtZCaDA",[1084,1090,1096],{"path":1085,"title":1086,"description":1087,"date":1088,"category":1089,"readingTime":362},"\u002Fblog\u002Fsecuriser-pipeline-gitlab-ci-devsecops","Sécuriser une pipeline GitLab CI\u002FCD sans ralentir vos livraisons","SAST, scan de dépendances et d'images, secrets, SBOM, signature cosign : comment intégrer la sécurité dans GitLab CI\u002FCD sans freiner vos mises en production.","2026-09-22","DevSecOps",{"path":1091,"title":1092,"description":1093,"date":1094,"category":1095,"readingTime":362},"\u002Fblog\u002Fseo-technique-nuxt","SEO technique avec Nuxt : le guide pour un site rapide et bien référencé","Rendu SSR ou pré-rendu, useSeoMeta, canoniques, sitemap, JSON-LD, Core Web Vitals : les réglages SEO techniques à maîtriser sur un site Nuxt 4.","2026-09-10","SEO",{"path":1097,"title":1098,"description":1099,"date":1100,"category":1101,"readingTime":362},"\u002Fblog\u002Fgitops-flux-kubernetes","GitOps avec Flux CD : piloter Kubernetes depuis Git, sans kubectl en production","GitOps avec Flux CD sur Kubernetes : structure de dépôt, Kustomization, HelmRelease, secrets SOPS, promotion entre environnements et validation en CI.","2026-08-28","Infrastructure",1792329028554]