Aller au contenu

Apache Cordova / Téléphonie Feuille de chaleur

Apache Cordova / PhoneGap - Développement d'applications mobiles hybrides

Apache Cordova (anciennement PhoneGap) est un cadre de développement d'applications mobiles qui permet aux développeurs de construire des applications mobiles natives en utilisant HTML, CSS et JavaScript. Il permet d'accéder aux API de périphérique natif via des plugins JavaScript.

Copier toutes les commandes Générer PDF

Sommaire

  • [Installation] (#installation)
  • [Pour commencer] (#getting-started)
  • [Structure du projet] (#project-structure)
  • [Commandes CLI] (#cli-commands)
  • [Gestion des programmes] (#platform-management)
  • [Système de lecture] (#plugin-system)
  • [Configuration] (#configuration)
  • API des appareils
  • [Cadres de l'UI] (#ui-frameworks)
  • [Travaux de développement] (#development-workflow)
  • [Bâtiment et essais] (#building-and-testing)
  • [Débogage] (#debugging)
  • [Optimisation du rendement] (#performance-optimization)
  • [Sécurité] (#security)
  • [Déploiement] (#deployment)
  • [Meilleures pratiques] (#best-practices)

Installation

Préalables

# Install Node.js (version 12 or later)
# Download from nodejs.org

# Verify Node.js installation
node --version
npm --version

# Install Java Development Kit (JDK) 8 or later
# Download from Oracle or use OpenJDK

# Install Android Studio (for Android development)
# Download from developer.android.com

# Install Xcode (for iOS development, macOS only)
# Download from Mac App Store

# Set environment variables
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/platform-tools

CLI Cordova Installation

# Install Cordova CLI globally
npm install -g cordova

# Verify installation
cordova --version

# Check requirements for platforms
cordova requirements

# Install platform-specific tools
# For Android
npm install -g gradle

# For iOS (macOS only)
npm install -g ios-deploy
```_

### Téléphonie CLI (alternative)
```bash
# Install PhoneGap CLI (Adobe's distribution)
npm install -g phonegap

# Verify installation
phonegap --version

# PhoneGap Build service (deprecated)
# Use Cordova CLI for new projects
```_

## Commencer

### Créer un nouveau projet
```bash
# Create new Cordova project
cordova create MyApp com.example.myapp "My App"

# Navigate to project directory
cd MyApp

# Add platforms
cordova platform add android
cordova platform add ios

# Add plugins
cordova plugin add cordova-plugin-device
cordova plugin add cordova-plugin-camera

# Build the app
cordova build

# Run on device/emulator
cordova run android
cordova run ios

Modèles de projet

# Create with specific template
cordova create MyApp com.example.myapp "My App" --template hello-world

# Create with custom template
cordova create MyApp com.example.myapp "My App" --template https://github.com/user/template.git

# Create blank project
cordova create MyApp com.example.myapp "My App" --template blank

# Create with TypeScript template
cordova create MyApp com.example.myapp "My App" --template cordova-template-typescript

Structure du projet

Structure de base

MyApp/
├── config.xml           # Cordova configuration
├── package.json         # Node.js dependencies
├── www/                 # Web assets
│   ├── index.html       # Main HTML file
│   ├── css/            # Stylesheets
│   ├── js/             # JavaScript files
│   └── img/            # Images
├── platforms/          # Platform-specific code (generated)
│   ├── android/
│   └── ios/
├── plugins/            # Installed plugins (generated)
├── hooks/              # Build hooks
└── res/                # Resources (icons, splash screens)
    ├── icon/
    └── screen/

Pour de plus amples informations, veuillez contacter:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <title>My App</title>
    <link rel="stylesheet" type="text/css" href="css/index.css">
</head>
<body>
    <div class="app">
        <h1>Apache Cordova</h1>
        <div id="deviceready" class="blink">
            <p class="event listening">Connecting to Device</p>
            <p class="event received">Device is Ready</p>
        </div>
    </div>
    <script type="text/javascript" src="cordova.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
</body>
</html>

Pour de plus amples informations, veuillez contacter:

var app = {
    // Application Constructor
    initialize: function() {
        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
    },

    // deviceready Event Handler
    onDeviceReady: function() {
        this.receivedEvent('deviceready');

        // Cordova is now initialized. Have fun!
        console.log('Running cordova-' + cordova.platformId + '@' + cordova.version);

        // Example: Get device information
        console.log('Device Model: ' + device.model);
        console.log('Device Platform: ' + device.platform);
        console.log('Device Version: ' + device.version);
    },

    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
    }
};

app.initialize();

CLI Commandes

Gestion de projet

# Create new project
cordova create <path> [id [name [config]]] [options]

# Add platform
cordova platform add <platform-name>
cordova platform add android
cordova platform add ios
cordova platform add browser

# Remove platform
cordova platform remove <platform-name>
cordova platform rm android

# List platforms
cordova platform list
cordova platform ls

# Update platform
cordova platform update <platform-name>

# Check platform version
cordova platform version

Gestion des greffons

# Add plugin
cordova plugin add <plugin-name>
cordova plugin add cordova-plugin-camera
cordova plugin add cordova-plugin-device

# Add plugin with variables
cordova plugin add cordova-plugin-facebook4 --variable APP_ID="123456789" --variable APP_NAME="myApplication"

# Remove plugin
cordova plugin remove <plugin-name>
cordova plugin rm cordova-plugin-camera

# List plugins
cordova plugin list
cordova plugin ls

# Search plugins
cordova plugin search camera

# Update plugin
cordova plugin update <plugin-name>

Construire et exécuter

# Build for all platforms
cordova build

# Build for specific platform
cordova build android
cordova build ios

# Build with options
cordova build android --release
cordova build ios --device

# Run on emulator
cordova emulate android
cordova emulate ios

# Run on device
cordova run android
cordova run ios

# Run with options
cordova run android --device
cordova run ios --target="iPhone-12"

# Serve for browser testing
cordova serve
cordova serve --port=8080

Commandes d'information

# Check requirements
cordova requirements

# Get help
cordova help
cordova help platform

# Check version
cordova --version
cordova -v

# Get info about project
cordova info

# List available templates
cordova template list

Gestion des plates-formes

Plateforme Android

# Add Android platform
cordova platform add android

# Build for Android
cordova build android

# Run on Android emulator
cordova emulate android

# Run on Android device
cordova run android --device

# Build release APK
cordova build android --release

# Build with specific API level
cordova build android --gradleArg=-PcdvBuildToolsVersion=28.0.3

# Clean Android build
cordova clean android

Plateforme iOS

# Add iOS platform (macOS only)
cordova platform add ios

# Build for iOS
cordova build ios

# Run on iOS simulator
cordova emulate ios

# Run on iOS device
cordova run ios --device

# Build for specific device
cordova build ios --device

# Build with provisioning profile
cordova build ios --codeSignIdentity="iPhone Developer" --provisioningProfile="UUID"

# Clean iOS build
cordova clean ios

Plateforme du navigateur

# Add browser platform
cordova platform add browser

# Run in browser
cordova run browser

# Serve for browser testing
cordova serve

# Build for browser
cordova build browser

Système de connexion

Greffons de base

# Device Information
cordova plugin add cordova-plugin-device

# Camera
cordova plugin add cordova-plugin-camera

# File System
cordova plugin add cordova-plugin-file

# Network Information
cordova plugin add cordova-plugin-network-information

# Geolocation
cordova plugin add cordova-plugin-geolocation

# Contacts
cordova plugin add cordova-plugin-contacts

# Media
cordova plugin add cordova-plugin-media

# File Transfer
cordova plugin add cordova-plugin-file-transfer

# InAppBrowser
cordova plugin add cordova-plugin-inappbrowser

# Dialogs
cordova plugin add cordova-plugin-dialogs

# Vibration
cordova plugin add cordova-plugin-vibration

# Battery Status
cordova plugin add cordova-plugin-battery-status

# Splash Screen
cordova plugin add cordova-plugin-splashscreen

# Status Bar
cordova plugin add cordova-plugin-statusbar

# Whitelist
cordova plugin add cordova-plugin-whitelist

Exemples d'utilisation du plugin

// Device Plugin
document.addEventListener("deviceready", function() {
    console.log("Device Model: " + device.model);
    console.log("Device Platform: " + device.platform);
    console.log("Device Version: " + device.version);
    console.log("Device UUID: " + device.uuid);
    console.log("Device Cordova: " + device.cordova);
}, false);

// Camera Plugin
function takePicture() {
    var options = {
        quality: 75,
        destinationType: Camera.DestinationType.FILE_URI,
        sourceType: Camera.PictureSourceType.CAMERA,
        encodingType: Camera.EncodingType.JPEG,
        targetWidth: 300,
        targetHeight: 300
    };

    navigator.camera.getPicture(onSuccess, onFail, options);

    function onSuccess(imageURI) {
        var image = document.getElementById('myImage');
        image.src = imageURI;
    }

    function onFail(message) {
        alert('Failed because: ' + message);
    }
}

// Geolocation Plugin
function getCurrentPosition() {
    var options = {
        enableHighAccuracy: true,
        timeout: 5000,
        maximumAge: 0
    };

    navigator.geolocation.getCurrentPosition(onSuccess, onError, options);

    function onSuccess(position) {
        console.log('Latitude: ' + position.coords.latitude);
        console.log('Longitude: ' + position.coords.longitude);
        console.log('Altitude: ' + position.coords.altitude);
        console.log('Accuracy: ' + position.coords.accuracy);
        console.log('Timestamp: ' + position.timestamp);
    }

    function onError(error) {
        alert('code: ' + error.code + '\n' + 'message: ' + error.message);
    }
}

// File Plugin
function writeFile() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getFile("test.txt", {create: true, exclusive: false}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                fileWriter.onwriteend = function() {
                    console.log("Successful file write...");
                };

                fileWriter.onerror = function(e) {
                    console.log("Failed file write: " + e.toString());
                };

                var dataObj = new Blob(['some file data'], { type: 'text/plain' });
                fileWriter.write(dataObj);
            });
        }, onErrorCreateFile);
    }, onErrorLoadFs);
}

// Network Information Plugin
function checkConnection() {
    var networkState = navigator.connection.type;

    var states = {};
    states[Connection.UNKNOWN]  = 'Unknown connection';
    states[Connection.ETHERNET] = 'Ethernet connection';
    states[Connection.WIFI]     = 'WiFi connection';
    states[Connection.CELL_2G]  = 'Cell 2G connection';
    states[Connection.CELL_3G]  = 'Cell 3G connection';
    states[Connection.CELL_4G]  = 'Cell 4G connection';
    states[Connection.CELL]     = 'Cell generic connection';
    states[Connection.NONE]     = 'No network connection';

    alert('Connection type: ' + states[networkState]);
}

Configuration

config.xml

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.myapp" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>My App</name>
    <description>
        A sample Apache Cordova application.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>

    <!-- Content source -->
    <content src="index.html" />

    <!-- Access control -->
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />

    <!-- Platform-specific configurations -->
    <platform name="android">
        <allow-intent href="market:*" />
        <icon density="ldpi" src="res/icon/android/ldpi.png" />
        <icon density="mdpi" src="res/icon/android/mdpi.png" />
        <icon density="hdpi" src="res/icon/android/hdpi.png" />
        <icon density="xhdpi" src="res/icon/android/xhdpi.png" />
        <icon density="xxhdpi" src="res/icon/android/xxhdpi.png" />
        <icon density="xxxhdpi" src="res/icon/android/xxxhdpi.png" />
        <splash density="land-ldpi" src="res/screen/android/splash-land-ldpi.png" />
        <splash density="land-mdpi" src="res/screen/android/splash-land-mdpi.png" />
        <splash density="land-hdpi" src="res/screen/android/splash-land-hdpi.png" />
        <splash density="land-xhdpi" src="res/screen/android/splash-land-xhdpi.png" />
        <splash density="land-xxhdpi" src="res/screen/android/splash-land-xxhdpi.png" />
        <splash density="land-xxxhdpi" src="res/screen/android/splash-land-xxxhdpi.png" />
        <splash density="port-ldpi" src="res/screen/android/splash-port-ldpi.png" />
        <splash density="port-mdpi" src="res/screen/android/splash-port-mdpi.png" />
        <splash density="port-hdpi" src="res/screen/android/splash-port-hdpi.png" />
        <splash density="port-xhdpi" src="res/screen/android/splash-port-xhdpi.png" />
        <splash density="port-xxhdpi" src="res/screen/android/splash-port-xxhdpi.png" />
        <splash density="port-xxxhdpi" src="res/screen/android/splash-port-xxxhdpi.png" />
    </platform>

    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
        <icon height="57" src="res/icon/ios/icon.png" width="57" />
        <icon height="114" src="res/icon/ios/icon@2x.png" width="114" />
        <icon height="40" src="res/icon/ios/icon-40.png" width="40" />
        <icon height="80" src="res/icon/ios/icon-40@2x.png" width="80" />
        <icon height="120" src="res/icon/ios/icon-40@3x.png" width="120" />
        <icon height="50" src="res/icon/ios/icon-50.png" width="50" />
        <icon height="100" src="res/icon/ios/icon-50@2x.png" width="100" />
        <icon height="60" src="res/icon/ios/icon-60.png" width="60" />
        <icon height="120" src="res/icon/ios/icon-60@2x.png" width="120" />
        <icon height="180" src="res/icon/ios/icon-60@3x.png" width="180" />
        <icon height="72" src="res/icon/ios/icon-72.png" width="72" />
        <icon height="144" src="res/icon/ios/icon-72@2x.png" width="144" />
        <icon height="76" src="res/icon/ios/icon-76.png" width="76" />
        <icon height="152" src="res/icon/ios/icon-76@2x.png" width="152" />
        <icon height="167" src="res/icon/ios/icon-83.5@2x.png" width="167" />
        <icon height="29" src="res/icon/ios/icon-small.png" width="29" />
        <icon height="58" src="res/icon/ios/icon-small@2x.png" width="58" />
        <icon height="87" src="res/icon/ios/icon-small@3x.png" width="87" />
        <splash height="1136" src="res/screen/ios/Default-568h@2x~iphone.png" width="640" />
        <splash height="1334" src="res/screen/ios/Default-667h.png" width="750" />
        <splash height="2208" src="res/screen/ios/Default-736h.png" width="1242" />
        <splash height="1242" src="res/screen/ios/Default-Landscape-736h.png" width="2208" />
        <splash height="1536" src="res/screen/ios/Default-Landscape@2x~ipad.png" width="2048" />
        <splash height="2048" src="res/screen/ios/Default-Landscape@~ipadpro.png" width="2732" />
        <splash height="768" src="res/screen/ios/Default-Landscape~ipad.png" width="1024" />
        <splash height="2048" src="res/screen/ios/Default-Portrait@2x~ipad.png" width="1536" />
        <splash height="2732" src="res/screen/ios/Default-Portrait@~ipadpro.png" width="2048" />
        <splash height="1024" src="res/screen/ios/Default-Portrait~ipad.png" width="768" />
        <splash height="960" src="res/screen/ios/Default@2x~iphone.png" width="640" />
        <splash height="480" src="res/screen/ios/Default~iphone.png" width="320" />
        <splash height="2732" src="res/screen/ios/Default@2x~universal~anyany.png" width="2732" />
    </platform>

    <!-- Preferences -->
    <preference name="DisallowOverscroll" value="true" />
    <preference name="android-minSdkVersion" value="19" />
    <preference name="BackupWebStorage" value="none" />
    <preference name="SplashMaintainAspectRatio" value="true" />
    <preference name="FadeSplashScreenDuration" value="300" />
    <preference name="SplashShowOnlyFirstTime" value="false" />
    <preference name="SplashScreen" value="screen" />
    <preference name="SplashScreenDelay" value="3000" />

    <!-- Plugin configurations -->
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <plugin name="cordova-plugin-statusbar" spec="2" />
    <plugin name="cordova-plugin-device" spec="2" />
    <plugin name="cordova-plugin-splashscreen" spec="5" />
    <plugin name="cordova-plugin-ionic-webview" spec="^4.0.0" />
    <plugin name="cordova-plugin-ionic-keyboard" spec="^2.0.5" />
</widget>

Plateforme spécifique Préférences

<!-- Android-specific preferences -->
<platform name="android">
    <preference name="android-minSdkVersion" value="19" />
    <preference name="android-targetSdkVersion" value="28" />
    <preference name="android-installLocation" value="auto" />
    <preference name="Orientation" value="portrait" />
    <preference name="Fullscreen" value="false" />
    <preference name="KeepRunning" value="true" />
    <preference name="LoadUrlTimeoutValue" value="20000" />
    <preference name="SplashScreen" value="splash" />
    <preference name="SplashScreenDelay" value="3000" />
    <preference name="InAppBrowserStorageEnabled" value="true" />
    <preference name="LoadingDialog" value="My Title,My Message" />
    <preference name="ErrorUrl" value="myErrorPage.html" />
    <preference name="ShowTitle" value="true" />
    <preference name="LogLevel" value="VERBOSE" />
</platform>

<!-- iOS-specific preferences -->
<platform name="ios">
    <preference name="CordovaWebViewEngine" value="CDVUIWebViewEngine" />
    <preference name="MinimumOSVersion" value="10.0" />
    <preference name="AllowInlineMediaPlayback" value="false" />
    <preference name="BackupWebStorage" value="none" />
    <preference name="TopActivityIndicator" value="gray" />
    <preference name="EnableViewportScale" value="false" />
    <preference name="KeyboardDisplayRequiresUserAction" value="true" />
    <preference name="SuppressesIncrementalRendering" value="false" />
    <preference name="SuppressesLongPressGesture" value="false" />
    <preference name="Suppresses3DTouchGesture" value="false" />
    <preference name="GapBetweenPages" value="0" />
    <preference name="PageLength" value="0" />
    <preference name="PaginationBreakingMode" value="page" />
    <preference name="PaginationMode" value="unpaginated" />
</platform>

API des périphériques

API de la caméra

// Take picture from camera
function capturePhoto() {
    var options = {
        quality: 50,
        destinationType: Camera.DestinationType.FILE_URI,
        sourceType: Camera.PictureSourceType.CAMERA,
        encodingType: Camera.EncodingType.JPEG,
        targetWidth: 300,
        targetHeight: 300,
        mediaType: Camera.MediaType.PICTURE,
        allowEdit: true,
        correctOrientation: true
    };

    navigator.camera.getPicture(onPhotoSuccess, onPhotoError, options);
}

// Select picture from gallery
function selectPhoto() {
    var options = {
        quality: 50,
        destinationType: Camera.DestinationType.FILE_URI,
        sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
        mediaType: Camera.MediaType.PICTURE,
        allowEdit: true,
        encodingType: Camera.EncodingType.JPEG,
        targetWidth: 300,
        targetHeight: 300
    };

    navigator.camera.getPicture(onPhotoSuccess, onPhotoError, options);
}

function onPhotoSuccess(imageURI) {
    var image = document.getElementById('myImage');
    image.src = imageURI;
}

function onPhotoError(message) {
    alert('Failed because: ' + message);
}

// Cleanup camera resources
function cleanup() {
    navigator.camera.cleanup(onSuccess, onFail);

    function onSuccess() {
        console.log("Camera cleanup success.")
    }

    function onFail(message) {
        alert('Failed because: ' + message);
    }
}

API de géolocalisation

// Get current position
function getCurrentLocation() {
    var options = {
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 60000
    };

    navigator.geolocation.getCurrentPosition(onLocationSuccess, onLocationError, options);
}

// Watch position changes
var watchID = null;

function watchLocation() {
    var options = {
        enableHighAccuracy: true,
        timeout: 30000,
        maximumAge: 60000
    };

    watchID = navigator.geolocation.watchPosition(onLocationSuccess, onLocationError, options);
}

function stopWatching() {
    if (watchID != null) {
        navigator.geolocation.clearWatch(watchID);
        watchID = null;
    }
}

function onLocationSuccess(position) {
    var element = document.getElementById('geolocation');
    element.innerHTML = 'Latitude: ' + position.coords.latitude + '<br />' +
                        'Longitude: ' + position.coords.longitude + '<br />' +
                        'Altitude: ' + position.coords.altitude + '<br />' +
                        'Accuracy: ' + position.coords.accuracy + '<br />' +
                        'Altitude Accuracy: ' + position.coords.altitudeAccuracy + '<br />' +
                        'Heading: ' + position.coords.heading + '<br />' +
                        'Speed: ' + position.coords.speed + '<br />' +
                        'Timestamp: ' + position.timestamp + '<br />';
}

function onLocationError(error) {
    alert('code: ' + error.code + '\n' + 'message: ' + error.message + '\n');
}

API du système de fichiers

// Request file system
function requestFileSystem() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, onFileSystemError);
}

function onFileSystemSuccess(fileSystem) {
    console.log(fileSystem.name);
    console.log(fileSystem.root.name);
}

function onFileSystemError(error) {
    console.log(error.code);
}

// Create file
function createFile() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getFile("newFile.txt", {create: true, exclusive: false}, function(fileEntry) {
            console.log("File created: " + fileEntry.fullPath);
        }, onErrorCreateFile);
    }, onErrorLoadFs);
}

// Write to file
function writeToFile() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getFile("newFile.txt", {create: true, exclusive: false}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                fileWriter.onwriteend = function() {
                    console.log("Successful file write...");
                    readFile();
                };

                fileWriter.onerror = function(e) {
                    console.log("Failed file write: " + e.toString());
                };

                var dataObj = new Blob(['some file data'], { type: 'text/plain' });
                fileWriter.write(dataObj);
            });
        }, onErrorCreateFile);
    }, onErrorLoadFs);
}

// Read file
function readFile() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getFile("newFile.txt", {}, function(fileEntry) {
            fileEntry.file(function(file) {
                var reader = new FileReader();

                reader.onloadend = function() {
                    console.log("Successful file read: " + this.result);
                    displayFileData(fileEntry.fullPath + ": " + this.result);
                };

                reader.readAsText(file);
            }, onErrorReadFile);
        }, onErrorCreateFile);
    }, onErrorLoadFs);
}

// Delete file
function deleteFile() {
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getFile("newFile.txt", {create: false}, function(fileEntry) {
            fileEntry.remove(function() {
                console.log("File deleted");
            }, onErrorDeleteFile);
        }, onErrorCreateFile);
    }, onErrorLoadFs);
}

function onErrorLoadFs(error) {
    console.log(error.code);
}

function onErrorCreateFile(error) {
    console.log(error.code);
}

function onErrorReadFile(error) {
    console.log(error.code);
}

function onErrorDeleteFile(error) {
    console.log(error.code);
}

function displayFileData(data) {
    document.getElementById("fileData").innerHTML = data;
}

API des contacts

// Create contact
function createContact() {
    var contact = navigator.contacts.create();
    contact.displayName = "Plumber";
    contact.nickname = "Plumber";

    var name = new ContactName();
    name.givenName = "Jane";
    name.familyName = "Doe";
    contact.name = name;

    var phoneNumbers = [];
    phoneNumbers[0] = new ContactField('work', '212-555-1234', false);
    phoneNumbers[1] = new ContactField('mobile', '917-555-5432', true);
    contact.phoneNumbers = phoneNumbers;

    var emails = [];
    emails[0] = new ContactField('work', 'jane_doe@company.com', false);
    contact.emails = emails;

    contact.save(onContactSaveSuccess, onContactSaveError);
}

function onContactSaveSuccess(contact) {
    alert("Save Success");
}

function onContactSaveError(contactError) {
    alert("Error = " + contactError.code);
}

// Find contacts
function findContacts() {
    var options = new ContactFindOptions();
    options.filter = "Bob";
    options.multiple = true;
    var fields = ["displayName", "name"];
    navigator.contacts.find(fields, onContactFindSuccess, onContactFindError, options);
}

function onContactFindSuccess(contacts) {
    for (var i = 0; i < contacts.length; i++) {
        console.log("Display Name = " + contacts[i].displayName);
    }
}

function onContactFindError(contactError) {
    alert('onError!');
}

// Clone contact
function cloneContact() {
    var clone = contact.clone();
    clone.name.givenName = "John";
    clone.save(onContactSaveSuccess, onContactSaveError);
}

// Remove contact
function removeContact() {
    contact.remove(onContactRemoveSuccess, onContactRemoveError);
}

function onContactRemoveSuccess() {
    alert("Removal Success");
}

function onContactRemoveError(contactError) {
    alert("Error = " + contactError.code);
}

Cadres d'assurance-chômage

jQuery Mobile Intégration

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>jQuery Mobile App</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css">
    <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
    <div data-role="page" id="home">
        <div data-role="header">
            <h1>My App</h1>
        </div>
        <div data-role="content">
            <ul data-role="listview" data-inset="true">
                <li><a href="#page2">Page 2</a></li>
                <li><a href="#page3">Page 3</a></li>
            </ul>
            <button onclick="takePicture()">Take Picture</button>
        </div>
        <div data-role="footer">
            <h4>Footer</h4>
        </div>
    </div>

    <div data-role="page" id="page2">
        <div data-role="header">
            <a href="#home" data-icon="arrow-l">Back</a>
            <h1>Page 2</h1>
        </div>
        <div data-role="content">
            <p>This is page 2</p>
        </div>
    </div>

    <script src="cordova.js"></script>
    <script src="js/index.js"></script>
</body>
</html>

Cadre7 Intégration

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <title>Framework7 App</title>
    <link rel="stylesheet" href="lib/framework7/css/framework7.bundle.min.css">
    <link rel="stylesheet" href="css/app.css">
</head>
<body>
    <div id="app">
        <div class="view view-main view-init" data-url="/">
            <div class="page" data-name="home">
                <div class="navbar">
                    <div class="navbar-bg"></div>
                    <div class="navbar-inner">
                        <div class="title">My App</div>
                    </div>
                </div>
                <div class="page-content">
                    <div class="block">
                        <p>Welcome to my Cordova app with Framework7!</p>
                        <a class="button button-fill" onclick="takePicture()">Take Picture</a>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="lib/framework7/js/framework7.bundle.min.js"></script>
    <script src="cordova.js"></script>
    <script src="js/app.js"></script>
</body>
</html>

Intégration du cadre ionique

# Install Ionic CLI
npm install -g @ionic/cli

# Create Ionic Cordova project
ionic start myApp tabs --type=angular --cordova

# Add platforms
ionic cordova platform add android
ionic cordova platform add ios

# Add plugins
ionic cordova plugin add cordova-plugin-camera

# Build and run
ionic cordova build android
ionic cordova run android

Développement Flux de travail

Recharger en direct

# Install live reload plugin
cordova plugin add cordova-plugin-browsersync

# Run with live reload
cordova run android --live-reload
cordova run ios --live-reload

# Serve for browser development
cordova serve
cordova serve --port=8080

# Use browser platform for quick testing
cordova platform add browser
cordova run browser

Pousser le code à chaud

# Install CodePush plugin
cordova plugin add cordova-plugin-code-push

# Configure CodePush
# Add to config.xml:
# <preference name="CodePushDeploymentKey" value="YOUR_DEPLOYMENT_KEY" />

# Release update
code-push release-cordova myApp-Android www 1.0.0
code-push release-cordova myApp-iOS www 1.0.0

Construire des crochets

// hooks/before_build/010_add_platform_class.js
module.exports = function(context) {
    var fs = require('fs');
    var path = require('path');

    var platformsMap = {
        'android': 'android',
        'ios': 'ios',
        'browser': 'browser'
    };

    var platforms = context.opts.cordova.platforms;

    platforms.forEach(function(platform) {
        var indexPath = path.join(context.opts.projectRoot, 'www', 'index.html');
        var indexContent = fs.readFileSync(indexPath, 'utf8');

        // Add platform-specific class to body
        var platformClass = platformsMap[platform];
        if (platformClass) {
            indexContent = indexContent.replace(
                /<body([^>]*)>/,
                '<body$1 class="platform-' + platformClass + '">'
            );

            fs.writeFileSync(indexPath, indexContent);
        }
    });
};

Configuration de l'environnement

// js/config.js
var Config = {
    development: {
        apiUrl: 'http://localhost:3000/api',
        debug: true
    },
    production: {
        apiUrl: 'https://api.myapp.com',
        debug: false
    }
};

// Detect environment
var environment = 'development';
if (window.location.protocol === 'file:') {
    environment = 'production';
}

var config = Config[environment];

// Usage
console.log('API URL:', config.apiUrl);
console.log('Debug mode:', config.debug);

Construction et essais

Constructions de débogage

# Build debug version
cordova build android
cordova build ios

# Run debug on device
cordova run android --device --debug
cordova run ios --device --debug

# Enable debugging
cordova build android --debug
cordova build ios --debug

Constructions de versions

# Build release version
cordova build android --release
cordova build ios --release

# Sign Android APK
# Generate keystore
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

# Sign APK
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk alias_name

# Align APK
zipalign -v 4 platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk MyApp.apk

Essais automatisés

// test/spec/test.js
describe('App Tests', function() {
    beforeEach(function(done) {
        document.addEventListener('deviceready', done, false);
    });

    it('should have device plugin', function() {
        expect(window.device).toBeDefined();
        expect(device.platform).toBeDefined();
    });

    it('should have camera plugin', function() {
        expect(navigator.camera).toBeDefined();
        expect(navigator.camera.getPicture).toBeDefined();
    });

    it('should take picture', function(done) {
        var options = {
            quality: 50,
            destinationType: Camera.DestinationType.FILE_URI,
            sourceType: Camera.PictureSourceType.CAMERA
        };

        navigator.camera.getPicture(
            function(imageURI) {
                expect(imageURI).toBeDefined();
                done();
            },
            function(error) {
                fail('Camera error: ' + error);
                done();
            },
            options
        );
    });
});

// Run tests with Jasmine
// Include jasmine.js and jasmine-html.js in test.html

Déboguement

Déboguage à distance

# Chrome DevTools for Android
# 1. Enable USB debugging on Android device
# 2. Connect device to computer
# 3. Open Chrome and go to chrome://inspect
# 4. Select your app from the list

# Safari Web Inspector for iOS
# 1. Enable Web Inspector on iOS device (Settings > Safari > Advanced)
# 2. Connect device to Mac
# 3. Open Safari > Develop > [Device Name] > [App Name]

# Weinre (Web Inspector Remote)
npm install -g weinre
weinre --boundHost 0.0.0.0 --httpPort 8080

# Add to index.html:
# <script src="http://YOUR_IP:8080/target/target-script-min.js#anonymous"></script>

Console Logging

// Enhanced console logging
var Logger = {
    log: function(message, data) {
        if (window.console) {
            console.log('[LOG] ' + message, data || '');
        }
        this.writeToFile('LOG', message, data);
    },

    error: function(message, error) {
        if (window.console) {
            console.error('[ERROR] ' + message, error || '');
        }
        this.writeToFile('ERROR', message, error);
    },

    warn: function(message, data) {
        if (window.console) {
            console.warn('[WARN] ' + message, data || '');
        }
        this.writeToFile('WARN', message, data);
    },

    writeToFile: function(level, message, data) {
        // Write logs to file for later analysis
        var logEntry = new Date().toISOString() + ' [' + level + '] ' + message;
        if (data) {
            logEntry += ' ' + JSON.stringify(data);
        }

        // Implementation depends on file plugin
        // this.appendToLogFile(logEntry);
    }
};

// Usage
Logger.log('App started');
Logger.error('Network error', error);
Logger.warn('Low battery', batteryLevel);

Gestion des erreurs

// Global error handler
window.onerror = function(message, source, lineno, colno, error) {
    Logger.error('Global error: ' + message, {
        source: source,
        line: lineno,
        column: colno,
        error: error
    });

    // Send error to analytics service
    // Analytics.trackError(message, source, lineno);

    return true; // Prevent default browser error handling
};

// Unhandled promise rejection handler
window.addEventListener('unhandledrejection', function(event) {
    Logger.error('Unhandled promise rejection', event.reason);
    event.preventDefault();
});

// Cordova-specific error handling
document.addEventListener('deviceready', function() {
    // Handle plugin errors
    if (window.plugins && window.plugins.toast) {
        window.plugins.toast.showShortTop = function(message) {
            try {
                window.plugins.toast.show(message, 'short', 'top');
            } catch (error) {
                Logger.error('Toast plugin error', error);
                alert(message); // Fallback
            }
        };
    }
}, false);

Optimisation des performances

Gestion de la mémoire

// Efficient DOM manipulation
var DOMUtils = {
    createElement: function(tag, attributes, content) {
        var element = document.createElement(tag);

        if (attributes) {
            for (var attr in attributes) {
                element.setAttribute(attr, attributes[attr]);
            }
        }

        if (content) {
            element.innerHTML = content;
        }

        return element;
    },

    removeElement: function(element) {
        if (element && element.parentNode) {
            element.parentNode.removeChild(element);
        }
    },

    clearElement: function(element) {
        while (element.firstChild) {
            element.removeChild(element.firstChild);
        }
    }
};

// Memory-efficient list rendering
var ListView = {
    render: function(container, items, itemRenderer) {
        // Clear existing content
        DOMUtils.clearElement(container);

        // Use document fragment for efficient DOM updates
        var fragment = document.createDocumentFragment();

        items.forEach(function(item, index) {
            var itemElement = itemRenderer(item, index);
            fragment.appendChild(itemElement);
        });

        container.appendChild(fragment);
    },

    renderVirtual: function(container, items, itemRenderer, visibleCount) {
        // Virtual scrolling for large lists
        var startIndex = 0;
        var endIndex = Math.min(visibleCount, items.length);

        DOMUtils.clearElement(container);

        for (var i = startIndex; i < endIndex; i++) {
            var itemElement = itemRenderer(items[i], i);
            container.appendChild(itemElement);
        }
    }
};

Optimisation de l'image

// Lazy loading images
var ImageLoader = {
    loadImage: function(src, callback) {
        var img = new Image();

        img.onload = function() {
            callback(null, img);
        };

        img.onerror = function() {
            callback(new Error('Failed to load image: ' + src));
        };

        img.src = src;
    },

    resizeImage: function(file, maxWidth, maxHeight, quality, callback) {
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var img = new Image();

        img.onload = function() {
            var ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
            canvas.width = img.width * ratio;
            canvas.height = img.height * ratio;

            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

            canvas.toBlob(callback, 'image/jpeg', quality);
        };

        img.src = URL.createObjectURL(file);
    },

    preloadImages: function(urls, callback) {
        var loaded = 0;
        var total = urls.length;
        var images = [];

        if (total === 0) {
            callback(null, images);
            return;
        }

        urls.forEach(function(url, index) {
            this.loadImage(url, function(error, img) {
                if (error) {
                    callback(error);
                    return;
                }

                images[index] = img;
                loaded++;

                if (loaded === total) {
                    callback(null, images);
                }
            });
        }.bind(this));
    }
};

Optimisation du réseau

// Network request manager
var NetworkManager = {
    cache: {},

    request: function(url, options, callback) {
        options = options || {};

        // Check cache first
        if (options.cache && this.cache[url]) {
            callback(null, this.cache[url]);
            return;
        }

        var xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    var response = xhr.responseText;

                    try {
                        response = JSON.parse(response);
                    } catch (e) {
                        // Response is not JSON
                    }

                    // Cache successful responses
                    if (options.cache) {
                        this.cache[url] = response;
                    }

                    callback(null, response);
                } else {
                    callback(new Error('HTTP ' + xhr.status + ': ' + xhr.statusText));
                }
            }
        }.bind(this);

        xhr.open(options.method || 'GET', url);

        // Set headers
        if (options.headers) {
            for (var header in options.headers) {
                xhr.setRequestHeader(header, options.headers[header]);
            }
        }

        xhr.send(options.body || null);
    },

    clearCache: function() {
        this.cache = {};
    },

    // Batch requests
    batch: function(requests, callback) {
        var completed = 0;
        var results = [];
        var hasError = false;

        requests.forEach(function(request, index) {
            this.request(request.url, request.options, function(error, response) {
                if (hasError) return;

                if (error) {
                    hasError = true;
                    callback(error);
                    return;
                }

                results[index] = response;
                completed++;

                if (completed === requests.length) {
                    callback(null, results);
                }
            });
        }.bind(this));
    }
};

Sécurité

Politique de sécurité du contenu

<!-- Add to index.html -->
<meta http-equiv="Content-Security-Policy" content="
    default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval';
    style-src 'self' 'unsafe-inline';
    media-src *;
    img-src 'self' data: content:;
    connect-src 'self' https://api.myapp.com;
    script-src 'self' 'unsafe-inline' 'unsafe-eval';
">

Stockage sécurisé

// Secure data storage
var SecureStorage = {
    encrypt: function(data, key) {
        // Use a proper encryption library like CryptoJS
        return CryptoJS.AES.encrypt(JSON.stringify(data), key).toString();
    },

    decrypt: function(encryptedData, key) {
        try {
            var bytes = CryptoJS.AES.decrypt(encryptedData, key);
            var decryptedData = bytes.toString(CryptoJS.enc.Utf8);
            return JSON.parse(decryptedData);
        } catch (error) {
            throw new Error('Failed to decrypt data');
        }
    },

    store: function(key, data, password) {
        var encryptedData = this.encrypt(data, password);
        localStorage.setItem(key, encryptedData);
    },

    retrieve: function(key, password) {
        var encryptedData = localStorage.getItem(key);
        if (!encryptedData) {
            return null;
        }

        return this.decrypt(encryptedData, password);
    },

    remove: function(key) {
        localStorage.removeItem(key);
    }
};

// Usage
SecureStorage.store('userToken', { token: 'abc123' }, 'myPassword');
var userData = SecureStorage.retrieve('userToken', 'myPassword');

Validation d'entrée

// Input validation utilities
var Validator = {
    email: function(email) {
        var regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return regex.test(email);
    },

    phone: function(phone) {
        var regex = /^\+?[\d\s\-\(\)]+$/;
        return regex.test(phone) && phone.replace(/\D/g, '').length >= 10;
    },

    url: function(url) {
        try {
            new URL(url);
            return true;
        } catch (error) {
            return false;
        }
    },

    sanitize: function(input) {
        return input.replace(/[<>'"&]/g, function(match) {
            var entities = {
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#x27;',
                '&': '&amp;'
            };
            return entities[match];
        });
    },

    length: function(input, min, max) {
        return input.length >= min && input.length <= max;
    },

    required: function(input) {
        return input !== null && input !== undefined && input.toString().trim() !== '';
    }
};

// Form validation
var FormValidator = {
    validate: function(form, rules) {
        var errors = {};

        for (var field in rules) {
            var value = form[field];
            var fieldRules = rules[field];

            for (var rule in fieldRules) {
                var ruleValue = fieldRules[rule];
                var isValid = false;

                switch (rule) {
                    case 'required':
                        isValid = ruleValue ? Validator.required(value) : true;
                        break;
                    case 'email':
                        isValid = ruleValue ? Validator.email(value) : true;
                        break;
                    case 'minLength':
                        isValid = value ? value.length >= ruleValue : true;
                        break;
                    case 'maxLength':
                        isValid = value ? value.length <= ruleValue : true;
                        break;
                }

                if (!isValid) {
                    errors[field] = errors[field] || [];
                    errors[field].push(rule);
                }
            }
        }

        return {
            isValid: Object.keys(errors).length === 0,
            errors: errors
        };
    }
};

// Usage
var formData = {
    email: 'user@example.com',
    password: '123456',
    name: 'John Doe'
};

var rules = {
    email: { required: true, email: true },
    password: { required: true, minLength: 6 },
    name: { required: true, maxLength: 50 }
};

var validation = FormValidator.validate(formData, rules);
if (!validation.isValid) {
    console.log('Validation errors:', validation.errors);
}

Déploiement

Déploiement de l'App Store

# iOS App Store
# 1. Build release version
cordova build ios --release

# 2. Open Xcode project
open platforms/ios/MyApp.xcworkspace

# 3. Configure signing and provisioning
# 4. Archive and upload to App Store Connect

# Google Play Store
# 1. Generate signed APK
cordova build android --release

# 2. Sign APK with keystore
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk alias_name

# 3. Align APK
zipalign -v 4 platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk MyApp.apk

# 4. Upload to Google Play Console

Distribution des entreprises

# iOS Enterprise Distribution
# 1. Build with enterprise certificate
cordova build ios --release

# 2. Create IPA file
# 3. Host on internal server with manifest.plist

# Android Enterprise Distribution
# 1. Build signed APK
cordova build android --release

# 2. Distribute through MDM or direct download

Intégration continue

# .github/workflows/build.yml
name: Build App

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Setup Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '14'

    - name: Install dependencies
      run: npm install

    - name: Install Cordova
      run: npm install -g cordova

    - name: Add platforms
      run: |
        cordova platform add android
        cordova platform add ios

    - name: Build Android
      run: cordova build android

    - name: Build iOS
      run: cordova build ios

    - name: Run tests
      run: npm test

    - name: Upload artifacts
      uses: actions/upload-artifact@v2
      with:
        name: builds
        path: platforms/*/build/

Meilleures pratiques

Organisation du projet

src/
├── js/
│   ├── app.js              # Main application logic
│   ├── config.js           # Configuration
│   ├── utils.js            # Utility functions
│   ├── services/           # API services
│   ├── models/             # Data models
│   └── views/              # View controllers
├── css/
│   ├── app.css             # Main styles
│   ├── components/         # Component styles
│   └── themes/             # Theme styles
├── templates/              # HTML templates
├── assets/
│   ├── images/
│   ├── fonts/
│   └── sounds/
└── tests/                  # Test files

Qualité du code

// Use strict mode
'use strict';

// Namespace your code
var MyApp = MyApp || {};

MyApp.Utils = {
    // Utility functions
};

MyApp.Services = {
    // Service functions
};

MyApp.Views = {
    // View controllers
};

// Use consistent error handling
MyApp.ErrorHandler = {
    handle: function(error, context) {
        console.error('Error in ' + context + ':', error);

        // Log to analytics service
        if (MyApp.Analytics) {
            MyApp.Analytics.trackError(error, context);
        }

        // Show user-friendly message
        if (navigator.notification) {
            navigator.notification.alert(
                'An error occurred. Please try again.',
                null,
                'Error',
                'OK'
            );
        } else {
            alert('An error occurred. Please try again.');
        }
    }
};

// Use consistent coding style
var MyApp = {
    init: function() {
        this.bindEvents();
        this.setupUI();
    },

    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
        document.addEventListener('pause', this.onPause.bind(this), false);
        document.addEventListener('resume', this.onResume.bind(this), false);
    },

    onDeviceReady: function() {
        console.log('Device ready');
        this.setupPlugins();
    },

    onPause: function() {
        console.log('App paused');
        this.saveState();
    },

    onResume: function() {
        console.log('App resumed');
        this.restoreState();
    },

    setupPlugins: function() {
        // Initialize plugins
    },

    setupUI: function() {
        // Setup user interface
    },

    saveState: function() {
        // Save application state
    },

    restoreState: function() {
        // Restore application state
    }
};

Lignes directrices en matière de résultats

// Optimize for mobile performance
var PerformanceOptimizer = {
    // Debounce function calls
    debounce: function(func, wait) {
        var timeout;
        return function() {
            var context = this;
            var args = arguments;
            clearTimeout(timeout);
            timeout = setTimeout(function() {
                func.apply(context, args);
            }, wait);
        };
    },

    // Throttle function calls
    throttle: function(func, limit) {
        var inThrottle;
        return function() {
            var args = arguments;
            var context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(function() {
                    inThrottle = false;
                }, limit);
            }
        };
    },

    // Optimize scroll events
    optimizeScroll: function(element, callback) {
        var ticking = false;

        function update() {
            callback();
            ticking = false;
        }

        function requestTick() {
            if (!ticking) {
                requestAnimationFrame(update);
                ticking = true;
            }
        }

        element.addEventListener('scroll', requestTick);
    },

    // Lazy load content
    lazyLoad: function(elements, callback) {
        var observer = new IntersectionObserver(function(entries) {
            entries.forEach(function(entry) {
                if (entry.isIntersecting) {
                    callback(entry.target);
                    observer.unobserve(entry.target);
                }
            });
        });

        elements.forEach(function(element) {
            observer.observe(element);
        });
    }
};

Résumé

Apache Cordova/PhoneGap fournit une plate-forme puissante pour le développement d'applications mobiles hybrides:

Avantages : - Plateforme de choc: Écrire une fois, exécuter sur plusieurs plateformes - Technologies Web: Utiliser HTML, CSS et JavaScript familiers - Écosystà ̈me Plugin: Accès aux fonctionnalités du périphérique natif via les plugins - Développement rapide: Cycle de développement plus rapide que les applications natives - Coût efficace: Base de code unique pour plusieurs plateformes

Cas de la meilleure utilisation: - Applications axées sur le contenu - Applications commerciales - Prototypes et MVP - Applications avec des exigences simples en matière d'assurance-chômage - Applications multiplateforme avec des fonctionnalités natives limitées

Considérations: - Les performances peuvent être plus lentes que les applications natives - Accès limité aux dernières fonctionnalités de la plate-forme - L'assurance-chômage peut ne pas être complètement native - Nécessite une optimisation soigneuse pour une performance en douceur

Cordova reste une option viable pour de nombreux projets d'applications mobiles, en particulier lorsque la vitesse de développement, le coût et la compatibilité entre les plateformes sont prioritaires par rapport aux performances maximales et à l'intégration des plateformes natives.