Définition
Apache Cordova permet la création d'applications pour téléphones en utilisant les technologies web HTML5, Typescript, Angular et CSS3 pour les plateformes Android et iOS.
Environnements
MacOS |
- compilation pour Android
- compilation pour iOS
- compilation pour Windows avec virtualisation
|
Windows |
- compilation pour Android, si Hyper-V ou Virtual Extension n'est pas lancé
car ils n'autorisent pas d'autres plateforme de virtualisation comme l'émulateur Android
- pas de compilation pour iOS sans Mac
- compilation pour Windows
|
Linux |
- compilation pour Android
- pas de compilation pour iOS sans Mac
- compilation pour Windows avec virtualisation
|
Installation
|
npm -g install cordova
npm -g install taco-cli
npm -g install ionic
|
- Android Studio
- Start a new project
- AVD Manager (Android Virtual Device)
- Create a Virtual Device
- XCode
- Visual Studio Code
|
cordova create myApp
cd myApp
cordova platforms ls
cordova platform add browser
cordova platform add android
cordova requirements
cordova build android --release
cordova emulate android
cordova run android --device
cordova run android --list
cordova run android --target=<target_name>
|
Signer le paquet *.apk
|
& 'C:\Program Files\Java\jdk1.8.0_162\bin\keytool.exe' -genkey -v -keystore myapp.keystore -alias MyApp -keyalg RSA -keysize 2048 -validity 10000
& 'C:\Program Files\Java\jdk1.8.0_162\bin\jarsigner.exe' -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore .\myapp.keystore .\android-release-unsigned.apk MyApp
|
|
/c/Program\ Files/Java/jdk1.8.0_162/bin/keytool.exe -genkey -v -keystore myapp.keystore -alias MyApp -keyalg RSA -keysize 2048 -validity 10000
cd MobileApp/platforms/android/build/outputs/apk/release
/c/Program\ Files/Java/jdk1.8.0_162/bin/jarsigner.exe -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore myapp.keystore android-release-unsigned.apk MyApp
/c/Users/llobera/AppData/Local/Android/Sdk/build-tools/27.0.3/zipalign.exe -v 4 android-release-unsigned.apk myapp.apk
|
Recherche de plugins
|
cordova plugin add <plugin-name>
cordova plugin remove <plugin-name>
|
package.json
|
"dependencies": {
"cordova-plugin-device": "^2.0.1"
},
"cordova": {
"plugins": {
"cordova-plugin-device": {}
}
}
|
cordova-plugin-device |
information sur le device
|
config.xml
|
<hook type="after_prepare" src="scripts/myScript.js" />
|
scripts/myScript.js
|
module.exports = function(ctx) {
if (ctx.opts.platforms.indexOf('android') < 0) {
return;
}
return deferral.promise;
};
|
Requêtes HTTP
|
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.setRequestHeader('Authorization', 'Bearer ' + accessToken);
req.onload = function(e) {
if (e.target.status >= 200 && e.target.status < 300) {
console.log("ok");
return;
}
console.log('Data request failed: ' + e.target.response);
};
req.onerror = function(e) {
console.log('Data request failed: ' + e.target.status);
}
req.onreadystatechange = function (oEvent) {
if (req.readyState === 4) {
if (req.status === 200) {
console.log(req.responseText)
} else {
console.log("Error", req.statusText);
}
}
};
req.send();
|
|
cordova.plugin.http.get(myUri, null,
{ Authorization: 'Bearer ' + accessToken },
function(response) {
console.log("Ok: " + response.status);
data = JSON.parse(response.data);
}, function(response) {
console.log("Ko: " + response.error);
});
|
|
cordova plugin add cordova-plugin-advanced-http
|
Angular
Code
|
<!DOCTYPE html>
<html>
<head>
<base href=".">
<title>Hello World</title>
<meta charset="UTF-8">
<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:;">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
</head>
<body>
<app>
Loading ...
</app>
<script src="cordova.js"></script>
<script src="dist/bundle.js"></script>
</body>
</html>
|
Installation
|
npm install --save @angular/common @angular/compiler @angular/core @angular/forms @angular/forms @angular/http @angular/platform-browser @angular/platform-browser-dynamic @angular/router @angular/upgrade angular-in-memory-web-api core-js reflect-metadata rxjs systemjs zone.js
npm install --save-dev @types/core-js @types/node concurrently lite-server typescript systemjs-plugin-text
|
package.json
|
{
"scripts": {
"start": "tsc && cordova run android",
"tsc": "tsc"
},
"dependencies": {
"@angular/common": "^5.2.9",
"@angular/compiler": "^5.2.9",
"@angular/core": "^5.2.9",
"@angular/forms": "^5.2.9",
"@angular/http": "^5.2.9",
"@angular/platform-browser": "^5.2.9",
"@angular/platform-browser-dynamic": "^5.2.9",
"@angular/router": "^5.2.9",
"@angular/upgrade": "^5.2.9",
"angular-in-memory-web-api": "^0.6.0",
"core-js": "^2.5.5",
"reflect-metadata": "^0.1.12",
"rxjs": "^5.5.8",
"systemjs": "^0.21.2",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@types/core-js": "^0.9.46",
"@types/node": "^9.6.2",
"concurrently": "^3.5.1",
"lite-server": "^2.3.0",
"systemjs-plugin-text": "0.0.11",
"typescript": "^2.8.1"
}
}
|
tsconfig.json
|
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "none",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": false,
"allowJs": false,
"forceConsistentCasingInFileNames": true
},
"exclude": [
"plugins",
"platforms",
"node_modules",
"hooks"
]
}
|
Android Studio
- SDK build tools %LocalAppData%\Android\Sdk\build-tools\27.0.3
- SDK platform tools %LocalAppData%\Android\Sdk\platform-tools
- JDK C:\Program Files\Java\jdk1.8.0_162\bin
- Android Virtual Device Manager: Bar de menu → droite → AVD Manager
Copier un fichier sur l'émulateur
Glisser-déposer le fichier à copier.
VScode
|
npm install
npm run cordova:run <ios/android>
cordova platform add android
npm install -g cordova
|
 |
- Installer Java SE Development Kit, puis ajouter C:\Program Files\Java\jdk1.8.0_162\bin au PATH
- Installer Android Studio
|
Debug Android
- Chrome → chrome://inspect → inspect link
- Sources → file:// → android_asset/www → js → index.js → ajouter un breakpoint
TACO - Tools for Apache COrdova
Debugger Android ou iOS device ou emulateur avec Visual Studio Code:
- VSCode → Extensions → Cordova Tools
- Debug → icône engrenage → Cordova (créé un fichier .vscode/launch.json)
- Debug → Run Android on emulator
- DEBUG CONSOLE
Exemple
www/index.html
|
<button id="populateDetailsButton">Populate</button>
<div id="deviceDetails"></div>
|
www/js/index.js
|
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
document.getElementById("populateDetailsButton").addEventListener(
"click", this.populateDeviceDetails
);
},
populateDeviceDetails: function() {
var deviceDetails = "";
deviceDetails += "<br/>Cordova:" + device.cordova;
deviceDetails += "<br/>Model:" + device.model;
deviceDetails += "<br/>Platform:" + device.platform;
document.querySelector("#deviceDetails").innerHTML = deviceDetails;
},
|
config.xml
|
<widget xmlns:android="http://schemas.android.com/apk/res/android">
<platform name="android">
<allow-intent href="market:*" />
<config-file parent="/*" target="AndroidManifest.xml">
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
</config-file>
</platform>
|
myApp\platforms\android\app\src\main\AndroidManifest.xml
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
|
cordova plugin add cordova-plugin-clipboard2
|
|
cordova.plugins.clipboard.copy(text);
cordova.plugins.clipboard.paste(function (text) { alert(text); });
|
Azure AD Cordova getting started
|
cordova plugin add cordova-plugin-whitelist
cordova plugin add cordova-plugin-ms-adal
|
|
authenticate: function (authCompletedCallback) {
app.context = new Microsoft.ADAL.AuthenticationContext(authority);
app.context.tokenCache.readItems().then(function (items) {
if (items.length > 0) {
authority = items[0].authority;
app.context = new Microsoft.ADAL.AuthenticationContext(authority);
}
app.context.acquireTokenSilentAsync(resourceUri, clientId)
.then(authCompletedCallback, function () {
app.context.acquireTokenAsync(resourceUri, clientId, redirectUri)
.then(authCompletedCallback, function (err) {
document.querySelector("#signInDetails").innerHTML = "Failed to authenticate: " + err;
app.error("Failed to authenticate: " + err);
});
});
});
},
requestData: function (authResult, searchText) {
var req = new XMLHttpRequest();
var url = resourceUri + "/v1.0/me";
req.open("GET", url, true);
req.setRequestHeader('Authorization', 'Bearer ' + authResult.accessToken);
req.onload = function(e) {
if (e.target.status >= 200 && e.target.status < 300) {
app.renderData(JSON.parse(e.target.response));
return;
}
app.error('Data request failed: ' + e.target.response);
};
req.onerror = function(e) {
app.error('Data request failed: ' + e.error);
}
req.send();
}
|
Authentification avec Azure AD, InTune et un broker
|
var redirectUri = "msauth://io.cordova.myapp/xxx-Signature-xxx",
Microsoft.ADAL.AuthenticationSettings.setUseBroker(true)
.then(function() {
app.authenticate(function(authResponse) {
app.log("Token acquired!<br/>Token will expire on: " + authResponse.expiresOn);
app.requestData(authResponse);
});
});
|
 |
Pour connaitre les redirectUri utiliser le script brokerRedirectPrint.ps1.
Il génère 2 uris, une uri de debug correspondant au keystore android C:\Users\$env:USERNAME\.android\debug.keystore
et une uri de release correspondant au keystore de l'application. |
com.microsoft.intune.mam.apppackager.utils.AppPackagerException: Failed to update this app's supported SDK versions.
com.microsoft.intune.mam.apppackager.utils.AppPackagerException: This app's target SDK is above the MAM target SDK. Please upgrade to the newest version of the App Wrapping Tool.
Wrapping failed for android
config.xml
|
<platform name="android">
<preference name="android-targetSdkVersion" value="24" />
|
Erreurs
ERROR in Error during template compile of 'ɵa'
Function calls are not supported in decorators but 'ɵmakeDecorator' was called in 'Injectable'
'Injectable' calls 'ɵmakeDecorator'.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
tsconfig.app.json
|
{
"compilerOptions": {
"paths": { "@angular/*": ["../node_modules/@angular/*"] }
}
}
|
list-devices is not recognized as an internal or external command
Available browser devices:
'myApp\platforms\browser\cordova\lib\list-devices' is not recognized as an internal or external command,
operable program or batch file.
An unexpected error has occured while running list-devices with code 1: Error: cmd: Command failed with exit code 1
Available browser virtual devices:
'myApp\platforms\browser\cordova\lib\list-emulator-images' is not recognized as an internal or external command,
operable program or batch file.
An unexpected error has occured while running list-emulator-images with code 1: Error: cmd: Command failed with exit code 1
|
cordova run android --list
|
ERROR: TypeError: Cannot read property 'semver' of null
Bug qui se produit avec les images android > 8.0 dans l'émulateur.
Supprimer ces images corrige le problème.