Dieses Dokument soll Ihnen den Einstieg in die Entwicklung von Chrome-Apps mit Sencha Ext JS erleichtern. Framework. Um dieses Ziel zu erreichen, sehen wir uns eine von Sencha entwickelte Mediaplayer-App an. Die Quelle Code und API-Dokumentation sind auf GitHub verfügbar.
Diese App erkennt die verfügbaren Medienserver eines Nutzers, einschließlich der mit dem PC verbundenen Mediengeräte und die Medien über das Netzwerk verwaltet. Nutzer können Medien durchsuchen, über das Netzwerk wiedergeben oder offline.
Im Folgenden sind die wichtigsten Schritte aufgeführt, die Sie ausführen müssen, um eine Mediaplayer-App mit Sencha Ext JS zu erstellen:
- Manifest erstellen:
manifest.json
. - Erstellen Sie die Veranstaltungsseite
background.js
. - der Sandbox-App.
- Kommunikation zwischen der Chrome-App und Dateien, die in einer Sandbox ausgeführt werden
- Medienserver ermitteln
- Medien entdecken und abspielen
- Medien offline speichern.
Manifest erstellen
Für alle Chrome-Apps ist eine Manifestdatei mit den Informationen erforderlich, die Chrome für den Start benötigt. Apps. Wie im Manifest angegeben, hat die Mediaplayer-App den Status „offline_enabled“. können Medien-Assets lokal gespeichert und unabhängig von der Internetverbindung abgerufen und wiedergegeben werden.
Die „Sandbox“ wird verwendet, um die Hauptlogik der App in einem eindeutigen Ursprung in einer Sandbox auszuführen. Alle in einer Sandbox ausgeführt Die Inhalte sind von den Content Security Policy für die Chrome App ausgenommen, können aber nicht direkt auf die APIs für Chrome-Apps Das Manifest enthält auch den "Socket" Berechtigung; verwendet die Mediaplayer-App Socket API, um über das Netzwerk eine Verbindung zu einem Medienserver herzustellen.
{
"name": "Video Player",
"description": "Features network media discovery and playlist management",
"version": "1.0.0",
"manifest_version": 2,
"offline_enabled": true,
"app": {
"background": {
"scripts": [
"background.js"
]
}
},
...
"sandbox": {
"pages": ["sandbox.html"]
},
"permissions": [
"experimental",
"http://*/*",
"unlimitedStorage",
{
"socket": [
"tcp-connect",
"udp-send-to",
"udp-bind"
]
}
]
}
Seite „Termin erstellen“
Alle Chrome-Apps erfordern background.js
zum Starten der Anwendung. Auf der Hauptseite des Mediaplayers
index.html
, wird in einem Fenster mit den angegebenen Abmessungen geöffnet:
chrome.app.runtime.onLaunched.addListener(function(launchData) {
var opt = {
width: 1000,
height: 700
};
chrome.app.window.create('index.html', opt, function (win) {
win.launchData = launchData;
});
});
Logik der Sandbox-App
Chrome-Apps werden in einer kontrollierten Umgebung ausgeführt, die eine strenge Content Security Policy erzwingt.
(CSP). Die Mediaplayer-App benötigt höhere Berechtigungen, um die externen JS-Komponenten zu rendern. Bis
CSP einhalten und die App-Logik ausführen, erstellt die Hauptseite der App (index.html
) einen iFrame, der
agiert als Sandbox-Umgebung:
<iframe id="sandbox-frame" sandbox="allow-scripts" src="sandbox.html"></iframe>
Der iFrame verweist auf sandbox.html. Diese Datei enthält die für das ext. JS erforderlichen Dateien. Anwendung:
<html>
<head>
<link rel="stylesheet" type="text/css" href="resources/css/app.css" />'
<script src="sdk/ext-all-dev.js"></script>'
<script src="lib/ext/data/PostMessage.js"></script>'
<script src="lib/ChromeProxy.js"></script>'
<script src="app.js"></script>
</head>
<body></body>
</html>
Das Skript app.js führt den gesamten externen JavaScript-Code aus und rendert die Mediaplayer-Ansichten. Da diese
in einer Sandbox ausgeführt wird, kann nicht direkt auf die APIs für Chrome-Apps zugegriffen werden. Kommunikation zwischen app.js
und Dateien ohne Sandbox werden mit der HTML5 Post Message API erstellt.
Kommunikation zwischen Dateien
Damit die Mediaplayer-App auf Chrome-App-APIs zugreifen kann, z. B. das Netzwerk nach Medien abfragen
Server sendet app.js
Nachrichten an index.js. Im Gegensatz zu app.js
in einer Sandbox kann index.js
direkt auf die APIs für Chrome-Apps zugreifen.
index.js
erstellt den iFrame:
var iframe = document.getElementById('sandbox-frame');
iframeWindow = iframe.contentWindow;
Und wartet auf Nachrichten aus den Dateien, die in einer Sandbox ausgeführt werden:
window.addEventListener('message', function(e) {
var data= e.data,
key = data.key;
console.log('[index.js] Post Message received with key ' + key);
switch (key) {
case 'extension-baseurl':
extensionBaseUrl(data);
break;
case 'upnp-discover':
upnpDiscover(data);
break;
case 'upnp-browse':
upnpBrowse(data);
break;
case 'play-media':
playMedia(data);
break;
case 'download-media':
downloadMedia(data);
break;
case 'cancel-download':
cancelDownload(data);
break;
default:
console.log('[index.js] unidentified key for Post Message: "' + key + '"');
}
}, false);
Im folgenden Beispiel sendet app.js
eine Nachricht an index.js
, in der der Schlüssel angefordert wird
"extension-baseurl":
Ext.data.PostMessage.request({
key: 'extension-baseurl',
success: function(data) {
//...
}
});
index.js
empfängt die Anfrage, weist das Ergebnis zu und antwortet, indem sie die Basis-URL zurücksendet:
function extensionBaseUrl(data) {
data.result = chrome.extension.getURL('/');
iframeWindow.postMessage(data, '*');
}
Medienserver ermitteln
Bei der Suche nach Medienservern geht es um sehr viel. Grundsätzlich ist der
Erkennungsworkflow
der durch eine Nutzeraktion initiiert wurde, um nach verfügbaren Medienservern zu suchen. Den MediaServer-Controller
postet eine Nachricht an index.js
; index.js
wartet auf diese Nachricht. Bei Eingang werden Anrufe entgegengenommen
Upnp.js:
Der Upnp library
verwendet die Socket API der Chrome App, um die Mediaplayer-App mit einem beliebigen
erkannte Medienserver und empfangen Mediendaten vom Medienserver. Upnp.js
verwendet auch
soapclient.js zum Parsen der Medienserverdaten. Im weiteren Verlauf dieses Abschnitts wird dies
auf den Workflow eingeht.
Nachricht posten
Wenn ein Nutzer in der Mitte der Mediaplayer-App auf die Schaltfläche „Medienserver“ klickt, MediaServers.js
ruft discoverServers()
auf. Diese Funktion prüft zuerst, ob ausstehende Erkennungsanfragen vorliegen.
true, bricht sie ab, sodass die neue Anfrage initiiert werden kann. Als Nächstes sendet der
Controller eine Nachricht an
index.js
mit einem upnp-Discovery-Schlüssel und zwei Callback-Listenern:
me.activeDiscoverRequest = Ext.data.PostMessage.request({
key: 'upnp-discover',
success: function(data) {
var items = [];
delete me.activeDiscoverRequest;
if (serversGraph.isDestroyed) {
return;
}
mainBtn.isLoading = false;
mainBtn.removeCls('pop-in');
mainBtn.setIconCls('ico-server');
mainBtn.setText('Media Servers');
//add servers
Ext.each(data, function(server) {
var icon,
urlBase = server.urlBase;
if (urlBase) {
if (urlBase.substr(urlBase.length-1, 1) === '/'){
urlBase = urlBase.substr(0, urlBase.length-1);
}
}
if (server.icons && server.icons.length) {
if (server.icons[1]) {
icon = server.icons[1].url;
}
else {
icon = server.icons[0].url;
}
icon = urlBase + icon;
}
items.push({
itemId: server.id,
text: server.friendlyName,
icon: icon,
data: server
});
});
...
},
failure: function() {
delete me.activeDiscoverRequest;
if (serversGraph.isDestroyed) {
return;
}
mainBtn.isLoading = false;
mainBtn.removeCls('pop-in');
mainBtn.setIconCls('ico-error');
mainBtn.setText('Error...click to retry');
}
});
upnpDiscover() aufrufen
index.js
wartet auf „upnp-discover“ Nachricht von app.js
und antwortet mit einem Anruf
upnpDiscover()
Wenn ein Medienserver erkannt wird, extrahiert index.js
die Medienserverdomain
aus den Parametern, speichert den Server lokal, formatiert die Medienserverdaten und überträgt die Daten per Push
den MediaServer
-Controller.
Medienserverdaten parsen
Wenn Upnp.js
einen neuen Medienserver erkennt, ruft er eine Beschreibung des Geräts ab und sendet
eine SOAP-Anfrage zum Suchen und Parsen der Medienserverdaten; soapclient.js
parst die Medienelemente
nach Tag-Namen in ein Dokument einfügen.
Verbindung zum Medienserver herstellen
Upnp.js
stellt eine Verbindung zu erkannten Medienservern her und empfängt Mediendaten über den Chrome App-Socket
API:
socket.create("udp", {}, function(info) {
var socketId = info.socketId;
//bind locally
socket.bind(socketId, "0.0.0.0", 0, function(info) {
//pack upnp message
var message = String.toBuffer(UPNP_MESSAGE);
//broadcast to upnp
socket.sendTo(socketId, message, UPNP_ADDRESS, UPNP_PORT, function(info) {
// Wait 1 second
setTimeout(function() {
//receive
socket.recvFrom(socketId, function(info) {
//unpack message
var data = String.fromBuffer(info.data),
servers = [],
locationReg = /^location:/i;
//extract location info
if (data) {
data = data.split("\r\n");
data.forEach(function(value) {
if (locationReg.test(value)){
servers.push(value.replace(locationReg, "").trim());
}
});
}
//success
callback(servers);
});
}, 1000);
});
});
});
Medien entdecken und abspielen
Der MediaExplorer-Controller listet alle Mediendateien in einem Medienserverordner auf und wird
ist für die Aktualisierung des Navigationspfads im Fenster der Mediaplayer-App verantwortlich. Wenn ein Nutzer
eine Mediendatei auswählt und der Controller eine Nachricht mit „play-media“ an index.js
sendet Schlüssel:
onFileDblClick: function(explorer, record) {
var serverPanel, node,
type = record.get('type'),
url = record.get('url'),
name = record.get('name'),
serverId= record.get('serverId');
if (type === 'audio' || type === 'video') {
Ext.data.PostMessage.request({
key : 'play-media',
params : {
url: url,
name: name,
type: type
}
});
}
},
index.js
wartet auf diese Nachricht und antwortet mit playMedia()
:
function playMedia(data) {
var type = data.params.type,
url = data.params.url,
playerCt = document.getElementById('player-ct'),
audioBody = document.getElementById('audio-body'),
videoBody = document.getElementById('video-body'),
mediaEl = playerCt.getElementsByTagName(type)[0],
mediaBody = type === 'video' ? videoBody : audioBody,
isLocal = false;
//save data
filePlaying = {
url : url,
type: type,
name: data.params.name
};
//hide body els
audioBody.style.display = 'none';
videoBody.style.display = 'none';
var animEnd = function(e) {
//show body el
mediaBody.style.display = '';
//play media
mediaEl.play();
//clear listeners
playerCt.removeEventListener( 'transitionend', animEnd, false );
animEnd = null;
};
//load media
mediaEl.src = url;
mediaEl.load();
//animate in player
playerCt.addEventListener( 'transitionend', animEnd, false );
playerCt.style.transform = "translateY(0)";
//reply postmessage
data.result = true;
sendMessage(data);
}
Medien offline speichern
Die Offlinespeicherung von Medien wird größtenteils von der filer.js-Bibliothek übernommen. Weitere Informationen im Artikel Einführung in filer.js lesen.
Der Prozess wird gestartet, wenn ein Nutzer eine oder mehrere Dateien auswählt und den Offlinezugriff einleitet. Aktion ausführen.
Der MediaExplorer-Controller sendet eine Nachricht mit dem Schlüssel 'download-media' an index.js
.
index.js
wartet auf diese Nachricht und ruft die Funktion downloadMedia()
auf, um den
Download-Prozess:
function downloadMedia(data) {
DownloadProcess.run(data.params.files, function() {
data.result = true;
sendMessage(data);
});
}
Die Methode DownloadProcess
des Dienstprogramms erstellt eine xhr-Anfrage zum Abrufen von Daten vom Medienserver und
wartet auf den Abschlussstatus. Dadurch wird der Onload-Callback initiiert, der den empfangenen Inhalt prüft.
und speichert die Daten lokal mit der Funktion filer.js
:
filer.write(
saveUrl,
{
data: Util.arrayBufferToBlob(fileArrayBuf),
type: contentType
},
function(fileEntry, fileWriter) {
console.log('file saved!');
//increment downloaded
me.completedFiles++;
//if reached the end, finalize the process
if (me.completedFiles === me.totalFiles) {
sendMessage({
key : 'download-progresss',
totalFiles : me.totalFiles,
completedFiles : me.completedFiles
});
me.completedFiles = me.totalFiles = me.percentage = me.downloadedFiles = 0;
delete me.percentages;
//reload local
loadLocalFiles(callback);
}
},
function(e) {
console.log(e);
}
);
Wenn der Download abgeschlossen ist, aktualisiert MediaExplorer
die Liste der Mediendateien und die Mediendatei
Baumansicht des Spielers.