Apache Cordova Mobile Entwicklungsbeispiele

Apache Cordova Hybrid Mobile App Entwicklungsbeispiele einschließlich Plugin-Nutzung, Geräte-APIs, Cross-Plattform-Bereitstellung und Legacy-System-Integration

💻 Cordova Core Plugins Implementierung javascript

🟢 simple

Wesentliche Cordova Core Plugins für Gerätefunktionen implementieren einschließlich Kamera, Geolocation, Benachrichtigungen, Dateisystem und Geräteinformationen

// config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.cordovaapp" version="1.0.0" xmlns="http://www.w3.org/ns/widgets">
    <name>CordovaDemo</name>
    <description>Apache Cordova Application</description>
    <author email="[email protected]" href="http://example.com">
        Example Developer
    </author>
    <content src="index.html" />
    <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:*" />

    <!-- Core Plugins -->
    <plugin name="cordova-plugin-camera" spec="^6.0.0" />
    <plugin name="cordova-plugin-geolocation" spec="^4.1.0" />
    <plugin name="cordova-plugin-device" spec="^2.1.0" />
    <plugin name="cordova-plugin-file" spec="^6.0.2" />
    <plugin name="cordova-plugin-file-transfer" spec="^1.7.1" />
    <plugin name="cordova-plugin-dialogs" spec="^2.0.2" />
    <plugin name="cordova-plugin-vibration" spec="^3.1.1" />
    <plugin name="cordova-plugin-network-information" spec="^2.0.2" />
    <plugin name="cordova-plugin-inappbrowser" spec="^3.2.0" />
    <plugin name="cordova-plugin-media-capture" spec="^3.0.3" />
    <plugin name="cordova-plugin-splashscreen" spec="^5.0.4" />
    <plugin name="cordova-plugin-statusbar" spec="^2.4.3" />
    <plugin name="cordova-plugin-whitelist" spec="^1.3.4" />

    <!-- Platform-specific preferences -->
    <platform name="android">
        <preference name="android-minSdkVersion" value="22" />
        <preference name="android-targetSdkVersion" value="30" />
        <preference name="SplashMaintainAspectRatio" value="true" />
        <preference name="SplashShowOnlyFirstTime" value="false" />
        <preference name="SplashScreenDelay" value="3000" />
        <preference name="StatusBarOverlaysWebView" value="false" />
        <preference name="StatusBarBackgroundColor" value="#000000" />
        <preference name="StatusBarStyle" value="lightcontent" />
    </platform>

    <platform name="ios">
        <preference name="SplashMaintainAspectRatio" value="true" />
        <preference name="SplashScreenDelay" value="3000" />
        <preference name="StatusBarOverlaysWebView" value="false" />
        <preference name="StatusBarBackgroundColor" value="#000000" />
        <preference name="StatusBarStyle" value="lightcontent" />
        <preference name="BackupWebStorage" value="none" />
    </platform>
</widget>

// js/services/CordovaDeviceService.js
class CordovaDeviceService {
    constructor() {
        this.isDeviceReady = false;
        this.initializeCordova();
    }

    initializeCordova() {
        document.addEventListener('deviceready', () => {
            console.log('Device is ready!');
            this.isDeviceReady = true;
            this.onDeviceReady();
        }, false);
    }

    onDeviceReady() {
        // Hide splash screen
        if (navigator.splashscreen) {
            navigator.splashscreen.hide();
        }

        // Setup status bar
        if (window.StatusBar) {
            StatusBar.backgroundColorByHexString("#000000");
            StatusBar.styleLightContent();
        }

        // Setup network monitoring
        this.setupNetworkMonitoring();
    }

    // Device Information
    getDeviceInfo() {
        if (!this.isDeviceReady) {
            console.warn('Device not ready');
            return null;
        }

        return {
            platform: device.platform,
            version: device.version,
            model: device.model,
            manufacturer: device.manufacturer,
            uuid: device.uuid,
            serial: device.serial,
            isVirtual: device.isVirtual
        };
    }

    // Camera Operations
    takePhoto(options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !navigator.camera) {
                reject(new Error('Camera not available'));
                return;
            }

            const defaultOptions = {
                quality: 80,
                destinationType: Camera.DestinationType.FILE_URI,
                sourceType: Camera.PictureSourceType.CAMERA,
                encodingType: Camera.EncodingType.JPEG,
                mediaType: Camera.MediaType.PICTURE,
                allowEdit: false,
                correctOrientation: true,
                saveToPhotoAlbum: false
            };

            const cameraOptions = { ...defaultOptions, ...options };

            navigator.camera.getPicture(
                (imageUri) => {
                    resolve({
                        success: true,
                        imageUri: imageUri,
                        message: 'Photo captured successfully'
                    });
                },
                (error) => {
                    reject(new Error(`Camera error: ${error}`));
                },
                cameraOptions
            );
        });
    }

    getPhotoFromGallery(options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !navigator.camera) {
                reject(new Error('Camera not available'));
                return;
            }

            const defaultOptions = {
                quality: 80,
                destinationType: Camera.DestinationType.FILE_URI,
                sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
                encodingType: Camera.EncodingType.JPEG,
                mediaType: Camera.MediaType.PICTURE
            };

            const cameraOptions = { ...defaultOptions, ...options };

            navigator.camera.getPicture(
                (imageUri) => {
                    resolve({
                        success: true,
                        imageUri: imageUri,
                        message: 'Photo selected successfully'
                    });
                },
                (error) => {
                    reject(new Error(`Gallery error: ${error}`));
                },
                cameraOptions
            );
        });
    }

    // Geolocation Operations
    getCurrentPosition(options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !navigator.geolocation) {
                reject(new Error('Geolocation not available'));
                return;
            }

            const defaultOptions = {
                maximumAge: 3000,
                timeout: 5000,
                enableHighAccuracy: true
            };

            const geolocationOptions = { ...defaultOptions, ...options };

            navigator.geolocation.getCurrentPosition(
                (position) => {
                    resolve({
                        success: true,
                        latitude: position.coords.latitude,
                        longitude: position.coords.longitude,
                        accuracy: position.coords.accuracy,
                        altitude: position.coords.altitude,
                        altitudeAccuracy: position.coords.altitudeAccuracy,
                        heading: position.coords.heading,
                        speed: position.coords.speed,
                        timestamp: position.timestamp
                    });
                },
                (error) => {
                    reject(new Error(`Geolocation error: ${error.message}`));
                },
                geolocationOptions
            );
        });
    }

    watchPosition(callback, options = {}) {
        if (!this.isDeviceReady || !navigator.geolocation) {
            throw new Error('Geolocation not available');
        }

        const defaultOptions = {
            maximumAge: 3000,
            timeout: 5000,
            enableHighAccuracy: true
        };

        const geolocationOptions = { ...defaultOptions, ...options };

        return navigator.geolocation.watchPosition(
            (position) => {
                callback({
                    success: true,
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude,
                    accuracy: position.coords.accuracy,
                    timestamp: position.timestamp
                });
            },
            (error) => {
                callback({
                    success: false,
                    error: error.message
                });
            },
            geolocationOptions
        );
    }

    // File System Operations
    readFile(path, options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !window.resolveLocalFileSystemURL) {
                reject(new Error('File system not available'));
                return;
            }

            window.resolveLocalFileSystemURL(
                path,
                (fileEntry) => {
                    fileEntry.file(
                        (file) => {
                            const reader = new FileReader();

                            reader.onloadend = function() {
                                resolve({
                                    success: true,
                                    data: this.result,
                                    name: file.name,
                                    size: file.size,
                                    type: file.type,
                                    lastModified: file.lastModified
                                });
                            };

                            reader.onerror = function() {
                                reject(new Error('Failed to read file'));
                            };

                            // Read based on options
                            if (options.asText) {
                                reader.readAsText(file);
                            } else if (options.asDataURL) {
                                reader.readAsDataURL(file);
                            } else {
                                reader.readAsArrayBuffer(file);
                            }
                        },
                        (error) => {
                            reject(new Error(`File error: ${error.code}`));
                        }
                    );
                },
                (error) => {
                    reject(new Error(`File system error: ${error.code}`));
                }
            );
        });
    }

    writeFile(path, data, options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !window.resolveLocalFileSystemURL) {
                reject(new Error('File system not available'));
                return;
            }

            const defaultOptions = {
                create: true,
                exclusive: false
            };

            const fileOptions = { ...defaultOptions, ...options };

            window.resolveLocalFileSystemURL(
                path.substring(0, path.lastIndexOf('/')),
                (directoryEntry) => {
                    directoryEntry.getFile(
                        path.substring(path.lastIndexOf('/') + 1),
                        fileOptions,
                        (fileEntry) => {
                            fileEntry.createWriter(
                                (writer) => {
                                    writer.onwriteend = () => {
                                        resolve({
                                            success: true,
                                            path: fileEntry.toURL(),
                                            message: 'File written successfully'
                                        });
                                    };

                                    writer.onerror = (error) => {
                                        reject(new Error(`Write error: ${error}`));
                                    };

                                    if (typeof data === 'string') {
                                        writer.write(data);
                                    } else if (data instanceof Blob) {
                                        writer.write(data);
                                    } else {
                                        const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
                                        writer.write(blob);
                                    }
                                },
                                (error) => {
                                    reject(new Error(`Writer error: ${error.code}`));
                                }
                            );
                        },
                        (error) => {
                            reject(new Error(`File creation error: ${error.code}`));
                        }
                    );
                },
                (error) => {
                    reject(new Error(`Directory error: ${error.code}`));
                }
            );
        });
    }

    // Dialog Operations
    showAlert(message, title = 'Alert', buttonName = 'OK') {
        return new Promise((resolve) => {
            if (!this.isDeviceReady || !navigator.notification) {
                // Fallback to browser alert
                alert(message);
                resolve();
                return;
            }

            navigator.notification.alert(
                message,
                () => resolve(),
                title,
                buttonName
            );
        });
    }

    showConfirm(message, title = 'Confirm', buttonLabels = ['OK', 'Cancel']) {
        return new Promise((resolve) => {
            if (!this.isDeviceReady || !navigator.notification) {
                // Fallback to browser confirm
                const result = confirm(message);
                resolve(result ? 1 : 2);
                return;
            }

            navigator.notification.confirm(
                message,
                (buttonIndex) => resolve(buttonIndex),
                title,
                buttonLabels
            );
        });
    }

    showPrompt(message, title = 'Prompt', buttonLabels = ['OK', 'Cancel'], defaultText = '') {
        return new Promise((resolve) => {
            if (!this.isDeviceReady || !navigator.notification) {
                // Fallback to browser prompt
                const result = prompt(message, defaultText);
                resolve(result ? { input1: result } : false);
                return;
            }

            navigator.notification.prompt(
                message,
                (results) => resolve(results),
                title,
                buttonLabels,
                defaultText
            );
        });
    }

    // Vibration
    vibrate(pattern) {
        if (!this.isDeviceReady || !navigator.notification || !navigator.vibrate) {
            console.warn('Vibration not available');
            return;
        }

        if (Array.isArray(pattern)) {
            navigator.notification.vibrateWithPattern(pattern);
        } else {
            navigator.vibrate(pattern || 1000);
        }
    }

    // Network Information
    setupNetworkMonitoring() {
        if (!this.isDeviceReady || !navigator.connection) {
            console.warn('Network information not available');
            return;
        }

        document.addEventListener('online', () => {
            console.log('Network connection established');
            this.onNetworkChange(true);
        });

        document.addEventListener('offline', () => {
            console.log('Network connection lost');
            this.onNetworkChange(false);
        });
    }

    onNetworkChange(isOnline) {
        // Override this method to handle network changes
        console.log(`Network status changed: ${isOnline ? 'online' : 'offline'}`);
    }

    getNetworkInfo() {
        if (!this.isDeviceReady || !navigator.connection) {
            return {
                online: navigator.onLine,
                type: 'unknown'
            };
        }

        const connection = navigator.connection;
        return {
            online: navigator.onLine,
            type: connection.type,
            effectiveType: connection.effectiveType,
            downlink: connection.downlink,
            rtt: connection.rtt
        };
    }

    // In App Browser
    openInAppBrowser(url, options = {}) {
        if (!this.isDeviceReady || !cordova.InAppBrowser) {
            // Fallback to opening in same window
            window.open(url, '_blank');
            return null;
        }

        const defaultOptions = {
            location: 'yes',
            clearcache: 'yes',
            toolbar: 'yes',
            closebuttoncaption: 'Close'
        };

        const browserOptions = { ...defaultOptions, ...options };
        const target = options.target || '_blank';

        return cordova.InAppBrowser.open(url, target, browserOptions);
    }

    // Media Capture
    captureAudio(options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !navigator.device.capture) {
                reject(new Error('Media capture not available'));
                return;
            }

            const defaultOptions = {
                limit: 1,
                duration: 30
            };

            const captureOptions = { ...defaultOptions, ...options };

            navigator.device.capture.captureAudio(
                (mediaFiles) => {
                    resolve({
                        success: true,
                        files: mediaFiles.map(file => ({
                            name: file.name,
                            fullPath: file.fullPath,
                            type: file.type,
                            lastModifiedDate: file.lastModifiedDate,
                            size: file.size
                        }))
                    });
                },
                (error) => {
                    reject(new Error(`Audio capture error: ${error.code}`));
                },
                captureOptions
            );
        });
    }

    captureImage(options = {}) {
        return new Promise((resolve, reject) => {
            if (!this.isDeviceReady || !navigator.device.capture) {
                reject(new Error('Media capture not available'));
                return;
            }

            const defaultOptions = {
                limit: 1
            };

            const captureOptions = { ...defaultOptions, ...options };

            navigator.device.capture.captureImage(
                (mediaFiles) => {
                    resolve({
                        success: true,
                        files: mediaFiles.map(file => ({
                            name: file.name,
                            fullPath: file.fullPath,
                            type: file.type,
                            lastModifiedDate: file.lastModifiedDate,
                            size: file.size
                        }))
                    });
                },
                (error) => {
                    reject(new Error(`Image capture error: ${error.code}`));
                },
                captureOptions
            );
        });
    }
}

// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
    module.exports = CordovaDeviceService;
}

// js/app.js (Main Application)
const deviceService = new CordovaDeviceService();

// Example usage in your app
class AppController {
    constructor() {
        this.initializeEventListeners();
    }

    initializeEventListeners() {
        document.addEventListener('DOMContentLoaded', () => {
            this.setupUI();
        });

        // Wait for device ready
        if (deviceService.isDeviceReady) {
            this.onDeviceReady();
        } else {
            document.addEventListener('deviceready', () => {
                this.onDeviceReady();
            });
        }
    }

    onDeviceReady() {
        console.log('App is ready!');
        this.displayDeviceInfo();
        this.checkNetworkStatus();
    }

    async displayDeviceInfo() {
        const deviceInfo = deviceService.getDeviceInfo();
        if (deviceInfo) {
            const infoElement = document.getElementById('device-info');
            if (infoElement) {
                infoElement.innerHTML = `
                    <p><strong>Platform:</strong> ${deviceInfo.platform}</p>
                    <p><strong>Version:</strong> ${deviceInfo.version}</p>
                    <p><strong>Model:</strong> ${deviceInfo.model}</p>
                    <p><strong>UUID:</strong> ${deviceInfo.uuid}</p>
                `;
            }
        }
    }

    checkNetworkStatus() {
        const networkInfo = deviceService.getNetworkInfo();
        const statusElement = document.getElementById('network-status');
        if (statusElement) {
            statusElement.innerHTML = `
                <p><strong>Status:</strong> ${networkInfo.online ? 'Online' : 'Offline'}</p>
                <p><strong>Type:</strong> ${networkInfo.type}</p>
            `;
            statusElement.className = networkInfo.online ? 'online' : 'offline';
        }
    }

    async takePicture() {
        try {
            const result = await deviceService.takePhoto({
                quality: 90,
                saveToPhotoAlbum: true
            });

            if (result.success) {
                const imageElement = document.getElementById('captured-image');
                if (imageElement) {
                    imageElement.src = result.imageUri;
                    imageElement.style.display = 'block';
                }

                await deviceService.showAlert(
                    'Photo captured successfully!',
                    'Success',
                    'OK'
                );
            }
        } catch (error) {
            console.error('Camera error:', error);
            await deviceService.showAlert(
                'Failed to capture photo: ' + error.message,
                'Error',
                'OK'
            );
        }
    }

    async getCurrentLocation() {
        try {
            const position = await deviceService.getCurrentPosition();

            if (position.success) {
                const locationElement = document.getElementById('location');
                if (locationElement) {
                    locationElement.innerHTML = `
                        <p><strong>Latitude:</strong> ${position.latitude}</p>
                        <p><strong>Longitude:</strong> ${position.longitude}</p>
                        <p><strong>Accuracy:</strong> ${position.accuracy}m</p>
                    `;
                }
            }
        } catch (error) {
            console.error('Geolocation error:', error);
            await deviceService.showAlert(
                'Failed to get location: ' + error.message,
                'Error',
                'OK'
            );
        }
    }

    async showConfirmation() {
        const result = await deviceService.showConfirm(
            'Do you want to continue?',
            'Confirmation',
            ['Yes', 'No']
        );

        if (result === 1) {
            await deviceService.showAlert('You chose Yes!', 'Result', 'OK');
        } else {
            await deviceService.showAlert('You chose No!', 'Result', 'OK');
        }
    }
}

// Initialize the app
const app = new AppController();

💻 Cordova Custom Plugin Entwicklung javascript

🟡 intermediate

Benutzerdefinierte Cordova Plugins mit nativen Code-Implementierungen für iOS (Objective-C/Swift) und Android (Java/Kotlin) erstellen

// Plugin Creation Command
// cordova plugin create cordova-plugin-myplugin --name "My Plugin" --plugin_id cordova-plugin-myplugin --plugin_version 1.0.0

// www/myplugin.js (JavaScript Interface)
var exec = require('cordova/exec');

var MyPlugin = {
    /**
     * Perform a custom operation
     * @param {Function} successCallback - Success callback
     * @param {Function} errorCallback - Error callback
     * @param {Object} options - Options object
     */
    customOperation: function(successCallback, errorCallback, options) {
        var defaultOptions = {
            value: '',
            mode: 'normal'
        };

        var mergedOptions = Object.assign(defaultOptions, options || {});

        exec(
            successCallback,
            errorCallback,
            'MyPlugin',
            'customOperation',
            [mergedOptions]
        );
    },

    /**
     * Get device specific information
     * @param {Function} successCallback - Success callback
     * @param {Function} errorCallback - Error callback
     */
    getDeviceInfo: function(successCallback, errorCallback) {
        exec(
            successCallback,
            errorCallback,
            'MyPlugin',
            'getDeviceInfo',
            []
        );
    },

    /**
     * Start monitoring a custom event
     * @param {Function} callback - Event callback
     */
    startMonitoring: function(callback) {
        exec(
            callback,
            callback,
            'MyPlugin',
            'startMonitoring',
            []
        );
    },

    /**
     * Stop monitoring custom events
     */
    stopMonitoring: function() {
        exec(
            function() {},
            function() {},
            'MyPlugin',
            'stopMonitoring',
            []
        );
    }
};

module.exports = MyPlugin;

// src/ios/MyPlugin.m (Objective-C Implementation)
#import <Cordova/CDV.h>
#import "MyPlugin.h"

@implementation MyPlugin

- (void)customOperation:(CDVInvokedUrlCommand*)command {
    CDVPluginResult* pluginResult = nil;
    NSString* value = nil;
    NSString* mode = @"normal";

    @try {
        // Get parameters
        NSDictionary* options = [command.arguments objectAtIndex:0];

        if (options) {
            value = [options objectForKey:@"value"];
            mode = [options objectForKey:@"mode"];

            if (!mode) {
                mode = @"normal";
            }
        }

        if (!value) {
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Missing required parameter: value"];
        } else {
            // Process the operation
            NSString* processedValue = [NSString stringWithFormat:@"%@: %@",
                                      [mode isEqualToString:@"advanced"] ? @"ADVANCED" : @"NORMAL",
                                      value];

            // Create response dictionary
            NSDictionary* result = @{
                @"success": @YES,
                @"processedValue": processedValue,
                @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000),
                @"platform": @"iOS"
            };

            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result];
        }
    } @catch (NSException* exception) {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception reason]];
    }

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)getDeviceInfo:(CDVInvokedUrlCommand*)command {
    CDVPluginResult* pluginResult = nil;

    @try {
        UIDevice* device = [UIDevice currentDevice];

        NSDictionary* deviceInfo = @{
            @"platform": @"iOS",
            @"systemVersion": device.systemVersion,
            @"model": device.model,
            @"name": device.name,
            @"customProperty": @"ios-specific-value",
            @"batteryLevel": @(device.batteryLevel),
            @"batteryState": @(device.batteryState)
        };

        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:deviceInfo];
    } @catch (NSException* exception) {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[exception reason]];
    }

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)startMonitoring:(CDVInvokedUrlCommand*)command {
    // Start monitoring custom events
    self.monitoringCallbackId = command.callbackId;

    // Example: Monitor battery changes
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(batteryLevelDidChange:)
                                                 name:UIDeviceBatteryLevelDidChangeNotification
                                               object:nil];

    // Enable battery monitoring
    [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];

    // Keep the command alive for monitoring
    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [pluginResult setKeepCallbackAsBool:YES];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)stopMonitoring:(CDVInvokedUrlCommand*)command {
    // Stop monitoring
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];

    self.monitoringCallbackId = nil;

    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)batteryLevelDidChange:(NSNotification*)notification {
    if (self.monitoringCallbackId) {
        UIDevice* device = [UIDevice currentDevice];

        NSDictionary* batteryInfo = @{
            @"eventType": @"batteryChange",
            @"level": @(device.batteryLevel),
            @"state": @(device.batteryState),
            @"timestamp": @([[NSDate date] timeIntervalSince1970] * 1000)
        };

        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:batteryInfo];
        [pluginResult setKeepCallbackAsBool:YES];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.monitoringCallbackId];
    }
}

- (void)dispose {
    [self stopMonitoring:nil];
    [super dispose];
}

@end

// src/android/MyPlugin.java (Android Implementation)
package com.example.myplugin;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.util.Log;

public class MyPlugin extends CordovaPlugin {
    private static final String TAG = "MyPlugin";
    private CallbackContext monitoringCallback;

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if ("customOperation".equals(action)) {
            this.customOperation(args, callbackContext);
            return true;
        } else if ("getDeviceInfo".equals(action)) {
            this.getDeviceInfo(callbackContext);
            return true;
        } else if ("startMonitoring".equals(action)) {
            this.startMonitoring(callbackContext);
            return true;
        } else if ("stopMonitoring".equals(action)) {
            this.stopMonitoring(callbackContext);
            return true;
        } else {
            callbackContext.error("Invalid action: " + action);
            return false;
        }
    }

    private void customOperation(JSONArray args, CallbackContext callbackContext) {
        try {
            if (args.length() < 1) {
                callbackContext.error("Missing options parameter");
                return;
            }

            JSONObject options = args.getJSONObject(0);
            String value = options.optString("value", "");
            String mode = options.optString("mode", "normal");

            if (value.isEmpty()) {
                callbackContext.error("Missing required parameter: value");
                return;
            }

            // Process the operation
            String processedValue = "advanced".equals(mode)
                ? "ADVANCED: " + value
                : "NORMAL: " + value;

            // Create response
            JSONObject result = new JSONObject();
            result.put("success", true);
            result.put("processedValue", processedValue);
            result.put("timestamp", System.currentTimeMillis());
            result.put("platform", "Android");

            callbackContext.success(result);
        } catch (JSONException e) {
            Log.e(TAG, "JSON Exception", e);
            callbackContext.error("JSON Exception: " + e.getMessage());
        }
    }

    private void getDeviceInfo(CallbackContext callbackContext) {
        try {
            Context context = cordova.getActivity().getApplicationContext();

            JSONObject deviceInfo = new JSONObject();
            deviceInfo.put("platform", "Android");
            deviceInfo.put("version", android.os.Build.VERSION.RELEASE);
            deviceInfo.put("model", android.os.Build.MODEL);
            deviceInfo.put("manufacturer", android.os.Build.MANUFACTURER);
            deviceInfo.put("customProperty", "android-specific-value");

            // Battery information
            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent batteryStatus = context.registerReceiver(null, ifilter);

            if (batteryStatus != null) {
                int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
                float batteryPct = level / (float) scale;
                int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);

                deviceInfo.put("batteryLevel", batteryPct);
                deviceInfo.put("batteryStatus", status);
            }

            callbackContext.success(deviceInfo);
        } catch (JSONException e) {
            Log.e(TAG, "JSON Exception", e);
            callbackContext.error("JSON Exception: " + e.getMessage());
        }
    }

    private void startMonitoring(CallbackContext callbackContext) {
        this.monitoringCallback = callbackContext;

        // Create a result that stays alive for monitoring
        PluginResult result = new PluginResult(PluginResult.Status.OK);
        result.setKeepCallback(true);
        callbackContext.sendPluginResult(result);

        // Start a background thread for monitoring
        startBackgroundMonitoring();
    }

    private void stopMonitoring(CallbackContext callbackContext) {
        this.monitoringCallback = null;
        stopBackgroundMonitoring();

        callbackContext.success();
    }

    private void startBackgroundMonitoring() {
        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                while (monitoringCallback != null) {
                    try {
                        // Example: Monitor battery every 5 seconds
                        Thread.sleep(5000);

                        if (monitoringCallback != null) {
                            Context context = cordova.getActivity().getApplicationContext();
                            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
                            Intent batteryStatus = context.registerReceiver(null, ifilter);

                            if (batteryStatus != null) {
                                int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
                                int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
                                float batteryPct = level / (float) scale;

                                JSONObject batteryInfo = new JSONObject();
                                try {
                                    batteryInfo.put("eventType", "batteryChange");
                                    batteryInfo.put("level", batteryPct);
                                    batteryInfo.put("timestamp", System.currentTimeMillis());

                                    PluginResult result = new PluginResult(PluginResult.Status.OK, batteryInfo);
                                    result.setKeepCallback(true);
                                    monitoringCallback.sendPluginResult(result);
                                } catch (JSONException e) {
                                    Log.e(TAG, "JSON Exception", e);
                                }
                            }
                        }
                    } catch (InterruptedException e) {
                        Log.d(TAG, "Monitoring interrupted", e);
                        break;
                    }
                }
            }
        });
    }

    private void stopBackgroundMonitoring() {
        // Cleanup background monitoring
        // This would typically involve stopping any background threads
    }

    @Override
    public void onDestroy() {
        stopMonitoring(null);
        super.onDestroy();
    }
}

// src/android/MyPlugin.gradle (Gradle Build File)
dependencies {
    implementation 'org.apache.cordova:framework:9.0.0'
}

// package.json (Plugin Package Configuration)
{
  "name": "cordova-plugin-myplugin",
  "version": "1.0.0",
  "description": "My Custom Cordova Plugin",
  "cordova": {
    "id": "cordova-plugin-myplugin",
    "platforms": [
      "android",
      "ios"
    ]
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/example/cordova-plugin-myplugin.git"
  },
  "keywords": [
    "cordova",
    "plugin",
    "ecosystem:cordova",
    "cordova-android",
    "cordova-ios"
  ],
  "author": "Example Developer",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/example/cordova-plugin-myplugin/issues"
  },
  "homepage": "https://github.com/example/cordova-plugin-myplugin#readme"
}

// Usage in Cordova App
// js/app.js
document.addEventListener('deviceready', function() {
    // Use the custom plugin
    MyPlugin.customOperation(
        function(result) {
            console.log('Success:', result);
        },
        function(error) {
            console.error('Error:', error);
        },
        {
            value: 'Hello World',
            mode: 'advanced'
        }
    );

    // Get device info
    MyPlugin.getDeviceInfo(
        function(deviceInfo) {
            console.log('Device Info:', deviceInfo);
        },
        function(error) {
            console.error('Error:', error);
        }
    );

    // Start monitoring
    MyPlugin.startMonitoring(function(event) {
        console.log('Event received:', event);
    });

    // Stop monitoring when done
    // MyPlugin.stopMonitoring();
});

💻 Cordova Enterprise Bereitstellung und Sicherheit javascript

🔴 complex

Enterprise-grade Cordova Apps konfigurieren mit Security-Best-Practices, Certificate Pinning, Verschlüsselung und Unternehmens-Bereitstellungsstrategien

// config-security.xml (Security Configuration)
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.enterprise.cordovaapp" version="2.0.0" xmlns="http://www.w3.org/ns/widgets">
    <name>EnterpriseApp</name>
    <description>Enterprise Cordova Application</description>
    <author email="[email protected]" href="https://enterprise.example.com">
        Enterprise Team
    </author>
    <content src="index.html" />

    <!-- Security Settings -->
    <access origin="https://api.enterprise.com" />
    <access origin="https://auth.enterprise.com" />
    <access origin="https://cdn.enterprise.com" />
    <allow-navigation href="https://*.enterprise.com/*" />
    <allow-intent href="https://*.enterprise.com/*" />
    <feature name="Whitelist">
        <param name="allowed-intents" value="https://*.enterprise.com/*" />
    </feature>

    <!-- Security Plugins -->
    <plugin name="cordova-plugin-advanced-http" spec="^3.2.2" />
    <plugin name="cordova-plugin-certificate-observer" spec="^1.0.0" />
    <plugin name="cordova-plugin-secure-storage" spec="^4.0.2" />
    <plugin name="cordova-plugin-screen-orientation" spec="^3.0.4" />
    <plugin name="cordova-plugin-app-version" spec="^0.1.9" />
    <plugin name="cordova-plugin-ios-security" spec="^2.0.0" />
    <plugin name="cordova-android-security" spec="^1.0.0" />

    <!-- Enterprise Platform Preferences -->
    <platform name="android">
        <preference name="android-minSdkVersion" value="23" />
        <preference name="android-targetSdkVersion" value="30" />
        <preference name="android:usesCleartextTraffic" value="false" />
        <preference name="android:networkSecurityConfig" value="res/xml/network_security_config.xml" />
        <preference name="android:allowBackup" value="false" />
        <preference name="android:fullBackupContent" value="false" />
        <preference name="AndroidInsecureFileModeEnabled" value="false" />

        <!-- Certificate Pinning -->
        <config-file target="AndroidManifest.xml" parent="/manifest/application">
            <meta-data android:name="io.intercom.certificate-pin" android:value="sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" />
        </config-file>
    </platform>

    <platform name="ios">
        <preference name="deployment-target" value="12.0" />
        <preference name="BackupWebStorage" value="none" />
        <preference name="DisallowOverscroll" value="true" />

        <!-- iOS Security Configuration -->
        <config-file target="*-Info.plist" parent="ITSAppUsesNonExemptEncryption">
            <true/>
        </config-file>

        <!-- App Transport Security -->
        <config-file target="*-Info.plist" parent="NSAppTransportSecurity">
            <dict>
                <key>NSAllowsArbitraryLoads</key>
                <false/>
                <key>NSExceptionDomains</key>
                <dict>
                    <key>api.enterprise.com</key>
                    <dict>
                        <key>NSExceptionRequiresForwardSecrecy</key>
                        <false/>
                        <key>NSExceptionMinimumTLSVersion</key>
                        <string>TLSv1.2</string>
                        <key>NSIncludesSubdomains</key>
                        <true/>
                    </dict>
                </dict>
            </dict>
        </config-file>
    </platform>
</widget>

// js/services/SecurityService.js
class SecurityService {
    constructor() {
        this.secureStorage = null;
        this.initializeSecurity();
    }

    async initializeSecurity() {
        try {
            // Initialize secure storage
            if (window.cordova && window.cordova.plugins.SecureStorage) {
                this.secureStorage = cordova.plugins.SecureStorage;
                await this.initializeSecureStorage();
            }

            // Setup certificate pinning
            await this.setupCertificatePinning();

            // Initialize encryption
            await this.initializeEncryption();
        } catch (error) {
            console.error('Security initialization failed:', error);
        }
    }

    async initializeSecureStorage() {
        return new Promise((resolve, reject) => {
            this.secureStorage.init(
                () => {
                    console.log('Secure storage initialized');
                    resolve();
                },
                (error) => {
                    console.error('Secure storage initialization failed:', error);
                    reject(error);
                },
                'enterprise_secure_storage'
            );
        });
    }

    async setupCertificatePinning() {
        if (!window.cordova || !window.cordova.plugins.CertificatePinning) {
            console.warn('Certificate pinning plugin not available');
            return;
        }

        return new Promise((resolve, reject) => {
            const certificates = [
                'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', // Primary certificate
                'sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=' // Backup certificate
            ];

            cordova.plugins.CertificatePinning.pinCertificates(
                certificates,
                () => {
                    console.log('Certificate pinning configured');
                    resolve();
                },
                (error) => {
                    console.error('Certificate pinning failed:', error);
                    reject(error);
                }
            );
        });
    }

    async initializeEncryption() {
        // Initialize AES encryption key
        this.encryptionKey = await this.getOrCreateEncryptionKey();
    }

    async getOrCreateEncryptionKey() {
        try {
            const existingKey = await this.getSecureItem('encryption_key');
            if (existingKey) {
                return existingKey;
            }

            // Generate new encryption key
            const key = this.generateEncryptionKey();
            await this.setSecureItem('encryption_key', key);
            return key;
        } catch (error) {
            console.error('Encryption key setup failed:', error);
            throw error;
        }
    }

    generateEncryptionKey() {
        // Generate a random 256-bit key
        const array = new Uint8Array(32);
        crypto.getRandomValues(array);
        return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
    }

    // Secure Storage Operations
    async setSecureItem(key, value) {
        if (!this.secureStorage) {
            throw new Error('Secure storage not available');
        }

        return new Promise((resolve, reject) => {
            this.secureStorage.set(
                () => resolve(),
                (error) => reject(error),
                key,
                value
            );
        });
    }

    async getSecureItem(key) {
        if (!this.secureStorage) {
            throw new Error('Secure storage not available');
        }

        return new Promise((resolve, reject) => {
            this.secureStorage.get(
                (value) => resolve(value),
                (error) => reject(error),
                key
            );
        });
    }

    async removeSecureItem(key) {
        if (!this.secureStorage) {
            throw new Error('Secure storage not available');
        }

        return new Promise((resolve, reject) => {
            this.secureStorage.remove(
                () => resolve(),
                (error) => reject(error),
                key
            );
        });
    }

    // Encryption/Decryption
    async encryptData(data) {
        try {
            const encoder = new TextEncoder();
            const dataBuffer = encoder.encode(JSON.stringify(data));

            // Import encryption key
            const key = await crypto.subtle.importKey(
                'raw',
                new TextEncoder().encode(this.encryptionKey).slice(0, 32),
                { name: 'AES-CBC' },
                false,
                ['encrypt']
            );

            // Generate random IV
            const iv = crypto.getRandomValues(new Uint8Array(16));

            // Encrypt data
            const encryptedData = await crypto.subtle.encrypt(
                {
                    name: 'AES-CBC',
                    iv: iv
                },
                key,
                dataBuffer
            );

            // Combine IV and encrypted data
            const combined = new Uint8Array(iv.length + encryptedData.byteLength);
            combined.set(iv);
            combined.set(new Uint8Array(encryptedData), iv.length);

            return btoa(String.fromCharCode.apply(null, combined));
        } catch (error) {
            console.error('Encryption failed:', error);
            throw error;
        }
    }

    async decryptData(encryptedData) {
        try {
            const combined = new Uint8Array(
                atob(encryptedData).split('').map(char => char.charCodeAt(0))
            );

            // Extract IV
            const iv = combined.slice(0, 16);
            const data = combined.slice(16);

            // Import encryption key
            const key = await crypto.subtle.importKey(
                'raw',
                new TextEncoder().encode(this.encryptionKey).slice(0, 32),
                { name: 'AES-CBC' },
                false,
                ['decrypt']
            );

            // Decrypt data
            const decryptedData = await crypto.subtle.decrypt(
                {
                    name: 'AES-CBC',
                    iv: iv
                },
                key,
                data
            );

            const decoder = new TextDecoder();
            return JSON.parse(decoder.decode(decryptedData));
        } catch (error) {
            console.error('Decryption failed:', error);
            throw error;
        }
    }

    // API Security
    async makeSecureRequest(url, options = {}) {
        const defaultOptions = {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'X-App-Version': await this.getAppVersion(),
                'X-Device-ID': await this.getDeviceId()
            },
            timeout: 30000
        };

        const requestOptions = { ...defaultOptions, ...options };

        try {
            // Add authentication token if available
            const authToken = await this.getSecureItem('auth_token');
            if (authToken) {
                requestOptions.headers['Authorization'] = `Bearer ${authToken}`;
            }

            // Make request with certificate pinning
            const response = await this.httpRequestWithPinning(url, requestOptions);
            return response;
        } catch (error) {
            console.error('Secure request failed:', error);
            throw error;
        }
    }

    async httpRequestWithPinning(url, options) {
        if (window.cordova && window.cordova.plugin.http) {
            // Use Cordova HTTP plugin with certificate pinning
            return new Promise((resolve, reject) => {
                cordova.plugin.http.setRequestSerializer('json');
                cordova.plugin.http.setResponseSerializer('json');

                const success = (response) => {
                    resolve({
                        status: response.status,
                        data: response.data,
                        headers: response.headers
                    });
                };

                const failure = (error) => {
                    reject(new Error(`HTTP Error: ${error.error}`));
                };

                if (options.method === 'GET') {
                    cordova.plugin.http.get(url, options.params || {}, options.headers, success, failure);
                } else if (options.method === 'POST') {
                    cordova.plugin.http.post(url, options.data || {}, options.headers, success, failure);
                } else if (options.method === 'PUT') {
                    cordova.plugin.http.put(url, options.data || {}, options.headers, success, failure);
                } else if (options.method === 'DELETE') {
                    cordova.plugin.http.delete(url, options.params || {}, options.headers, success, failure);
                }
            });
        } else {
            // Fallback to standard fetch with security considerations
            const response = await fetch(url, options);

            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }

            return {
                status: response.status,
                data: await response.json(),
                headers: response.headers
            };
        }
    }

    async getAppVersion() {
        return new Promise((resolve, reject) => {
            if (window.cordova && window.cordova.getVersionCode) {
                window.cordova.getVersionCode(
                    (version) => resolve(version),
                    (error) => reject(error)
                );
            } else {
                resolve('1.0.0'); // Fallback version
            }
        });
    }

    async getDeviceId() {
        try {
            let deviceId = await this.getSecureItem('device_id');
            if (!deviceId) {
                deviceId = this.generateDeviceId();
                await this.setSecureItem('device_id', deviceId);
            }
            return deviceId;
        } catch (error) {
            console.error('Failed to get device ID:', error);
            return 'unknown';
        }
    }

    generateDeviceId() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    // Session Management
    async createSession(userCredentials) {
        try {
            // Authenticate with backend
            const authResponse = await this.makeSecureRequest(
                'https://api.enterprise.com/auth/login',
                {
                    method: 'POST',
                    data: userCredentials
                }
            );

            if (authResponse.status === 200 && authResponse.data.token) {
                // Securely store authentication tokens
                await this.setSecureItem('auth_token', authResponse.data.token);
                await this.setSecureItem('refresh_token', authResponse.data.refreshToken);

                // Encrypt and store user session data
                const encryptedSession = await this.encryptData({
                    user: authResponse.data.user,
                    permissions: authResponse.data.permissions,
                    expiresAt: Date.now() + (authResponse.data.expiresIn * 1000)
                });

                await this.setSecureItem('user_session', encryptedSession);

                return authResponse.data;
            } else {
                throw new Error('Authentication failed');
            }
        } catch (error) {
            console.error('Session creation failed:', error);
            throw error;
        }
    }

    async validateSession() {
        try {
            const encryptedSession = await this.getSecureItem('user_session');
            if (!encryptedSession) {
                return false;
            }

            const session = await this.decryptData(encryptedSession);

            // Check if session is expired
            if (session.expiresAt < Date.now()) {
                await this.clearSession();
                return false;
            }

            // Validate token with backend
            const validationResponse = await this.makeSecureRequest(
                'https://api.enterprise.com/auth/validate',
                {
                    method: 'POST',
                    data: { token: await this.getSecureItem('auth_token') }
                }
            );

            return validationResponse.status === 200;
        } catch (error) {
            console.error('Session validation failed:', error);
            await this.clearSession();
            return false;
        }
    }

    async clearSession() {
        try {
            await this.removeSecureItem('auth_token');
            await this.removeSecureItem('refresh_token');
            await this.removeSecureItem('user_session');
            await this.removeSecureItem('device_id');
        } catch (error) {
            console.error('Session cleanup failed:', error);
        }
    }

    // Audit Logging
    async logSecurityEvent(eventType, details) {
        try {
            const auditLog = {
                timestamp: new Date().toISOString(),
                eventType: eventType,
                details: details,
                deviceId: await this.getDeviceId(),
                appVersion: await this.getAppVersion()
            };

            // Encrypt audit log
            const encryptedLog = await this.encryptData(auditLog);

            // Send to secure logging endpoint
            await this.makeSecureRequest(
                'https://api.enterprise.com/audit/log',
                {
                    method: 'POST',
                    data: { log: encryptedLog }
                }
            );
        } catch (error) {
            console.error('Security event logging failed:', error);
        }
    }
}

// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
    module.exports = SecurityService;
}

// js/EnterpriseApp.js (Main Application)
class EnterpriseApp {
    constructor() {
        this.securityService = new SecurityService();
        this.isAuthenticated = false;
    }

    async initialize() {
        try {
            // Validate existing session
            this.isAuthenticated = await this.securityService.validateSession();

            if (this.isAuthenticated) {
                await this.loadUserData();
                await this.showMainInterface();
            } else {
                await this.showLoginInterface();
            }

            // Log app initialization
            await this.securityService.logSecurityEvent('APP_INITIALIZED', {
                timestamp: Date.now(),
                existingSession: this.isAuthenticated
            });

        } catch (error) {
            console.error('App initialization failed:', error);
            await this.handleInitializationError(error);
        }
    }

    async login(username, password) {
        try {
            const credentials = {
                username: username,
                password: password,
                deviceId: await this.securityService.getDeviceId(),
                timestamp: Date.now()
            };

            const session = await this.securityService.createSession(credentials);
            this.isAuthenticated = true;

            await this.securityService.logSecurityEvent('USER_LOGIN', {
                username: username,
                success: true
            });

            await this.loadUserData();
            await this.showMainInterface();

            return session;
        } catch (error) {
            await this.securityService.logSecurityEvent('LOGIN_FAILED', {
                username: username,
                error: error.message
            });

            throw error;
        }
    }

    async logout() {
        try {
            await this.securityService.logSecurityEvent('USER_LOGOUT', {
                timestamp: Date.now()
            });

            await this.securityService.clearSession();
            this.isAuthenticated = false;

            await this.showLoginInterface();
        } catch (error) {
            console.error('Logout failed:', error);
        }
    }

    async loadUserData() {
        // Load user-specific data securely
    }

    async showMainInterface() {
        // Show main application interface
    }

    async showLoginInterface() {
        // Show login interface
    }

    async handleInitializationError(error) {
        // Handle initialization errors
        console.error('Initialization error:', error);
        await this.securityService.logSecurityEvent('INIT_ERROR', {
            error: error.message
        });
    }
}

// Initialize the enterprise app
document.addEventListener('deviceready', () => {
    const app = new EnterpriseApp();
    app.initialize();
});