El objetivo de este documento es ayudarte a comenzar a compilar apps de Chrome con la herramienta Sencha Ext JS. en un framework de aplicaciones. Para lograr este objetivo, nos sumergiremos en una app de reproducción multimedia creada por Sencha. La fuente código y la documentación de la API están disponibles en GitHub.
Esta app descubre los servidores de medios disponibles del usuario, incluidos los dispositivos multimedia conectados a la PC y software que administra contenido multimedia a través de la red. Los usuarios pueden explorar contenido multimedia, reproducir contenido en la red o guardar contenido sin conexión.
Aquí están los pasos clave que debes seguir para compilar una app de reproducción multimedia con Sencha Ext JS:
- Crear manifiesto,
manifest.json
. - Crear página del evento,
background.js
- Es la lógica de la app de zona de pruebas.
- Comunicación entre la app de Chrome y los archivos de la zona de pruebas
- Detecta servidores de contenido multimedia.
- Explora y reproduce contenido multimedia.
- Guardar contenido multimedia sin conexión
Crear manifiesto
Todas las Apps de Chrome requieren un archivo de manifiesto que contenga la información que Chrome necesita para iniciarse. de Google Chat. Como se indica en el manifiesto, la app de reproducción multimedia está "offline_enabled". los recursos multimedia se guardan localmente, se accede a ellos y se reproducen sin importar la conectividad.
La "zona de pruebas" se usa para realizar una zona de pruebas de la lógica principal de la app en un origen único. Todas las zonas de pruebas contenido está exento de la Política de Seguridad del Contenido de las Apps de Chrome, pero no puede acceder directamente a APIs de la app de Chrome. El manifiesto también incluye el "socket" permiso; la app de reproducción multimedia usa el API de socket para conectarse a un servidor multimedia a través de la red.
{
"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"
]
}
]
}
Página para crear evento
Todas las Apps de Chrome requieren background.js
para iniciar la aplicación. La página principal del reproductor multimedia
index.html
se abre en una ventana con las dimensiones especificadas:
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;
});
});
Lógica de la app de zona de pruebas
Las Apps de Chrome se ejecutan en un entorno controlado que aplica una Política de Seguridad del Contenido estricta
(CSP). La app de reproductor multimedia necesita algunos privilegios más altos para procesar los componentes de Ext JS. Para
cumplir con la CSP y ejecutar la lógica de la app, la página principal de la app, index.html
, crea un iframe que
que funciona como un entorno de zona de pruebas:
<iframe id="sandbox-frame" sandbox="allow-scripts" src="sandbox.html"></iframe>
El iframe dirige a sandbox.html, que incluye los archivos necesarios para la extensión JS aplicación:
<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>
La secuencia de comandos app.js ejecuta todo el código de JS externo y procesa las vistas del reproductor multimedia. Desde este
secuencia de comandos está en zona de pruebas, no puede acceder directamente a las API de las aplicaciones de Chrome. Comunicación entre app.js
y que no están incluidos en la zona de pruebas se realiza con la API de HTML5 Post Message.
Cómo comunicarse entre archivos
Para que la app de reproductor multimedia acceda a las APIs de la app de Chrome, como consultar el contenido multimedia en la red
servidores, app.js
publica mensajes en index.js. A diferencia de la zona de pruebas app.js
, index.js
puede
acceder directamente a las APIs de la aplicación de Chrome.
index.js
crea el iframe:
var iframe = document.getElementById('sandbox-frame');
iframeWindow = iframe.contentWindow;
Además, detecta los mensajes de los archivos de la zona de pruebas:
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);
En el siguiente ejemplo, app.js
envía un mensaje a index.js
para solicitar la clave.
"extension-baseurl":
Ext.data.PostMessage.request({
key: 'extension-baseurl',
success: function(data) {
//...
}
});
index.js
recibe la solicitud, asigna el resultado y responde enviando la URL base:
function extensionBaseUrl(data) {
data.result = chrome.extension.getURL('/');
iframeWindow.postMessage(data, '*');
}
Cómo detectar servidores multimedia
Hay mucho que explorar para descubrir servidores de medios. En términos generales, el flujo de trabajo del descubrimiento
que se inicia con una acción del usuario para buscar servidores de medios disponibles. El controlador MediaServer
publica un mensaje en index.js
; index.js
escucha este mensaje y, cuando lo reciba, las llamadas
Upnp.js.
El Upnp library
usa la API de socket de la app de Chrome para conectar la app del reproductor multimedia con cualquier
de servidores de medios detectados
y recibir datos de medios del servidor. Upnp.js
también usa
soapclient.js para analizar los datos del servidor multimedia. En el resto de esta sección, se describe
de Terraform en mayor detalle.
Publicar mensaje
Cuando un usuario hace clic en el botón Servidores multimedia, en el centro de la app del reproductor multimedia, MediaServers.js
llama a discoverServers()
. Esta función primero comprueba si hay solicitudes de descubrimiento pendientes y,
true, las anula para que se pueda iniciar la nueva solicitud. Luego, el controlador publica un mensaje para
index.js
con una clave upnp-discovery y dos objetos de escucha de devolución de llamada:
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');
}
});
Llama a upnpDiscover()
index.js
escucha "upnp-discover" mensaje de app.js
y responde llamando
upnpDiscover()
Cuando se detecta un servidor multimedia, index.js
extrae el dominio del servidor multimedia.
de los parámetros, guarda el servidor de forma local, formatea los datos del servidor multimedia y envía los datos a
el controlador de MediaServer
.
Analizar datos del servidor multimedia
Cuando Upnp.js
descubre un nuevo servidor multimedia, recupera una descripción del dispositivo y envía
una solicitud de Soaprequest para navegar y analizar los datos del servidor de medios; soapclient.js
analiza los elementos multimedia.
por nombre de etiqueta en un documento.
Conectar al servidor multimedia
Upnp.js
se conecta a los servidores de contenido multimedia descubiertos y recibe datos multimedia mediante el socket de la app de Chrome.
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);
});
});
});
Explora y reproduce contenido multimedia
El controlador MediaExplorer muestra todos los archivos multimedia dentro de una carpeta del servidor multimedia.
Es responsable de actualizar la navegación de la ruta de navegación en la ventana de la app del reproductor multimedia. Cuando un usuario
selecciona un archivo multimedia, el controlador publica un mensaje para index.js
con el comando "play-media" clave:
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
escucha este mensaje de publicación y responde llamando a 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);
}
Cómo guardar contenido multimedia sin conexión
La mayor parte del trabajo difícil para guardar contenido multimedia sin conexión lo realiza la biblioteca de filer.js. Más información esta biblioteca en Introducing filer.js.
El proceso se inicia cuando un usuario selecciona uno o más archivos e inicia la función "Quitar sin conexión". acción.
El controlador de MediaExplorer publica un mensaje en index.js
con la clave "download-media".
index.js
escucha este mensaje y llama a la función downloadMedia()
para iniciar la
proceso de descarga:
function downloadMedia(data) {
DownloadProcess.run(data.params.files, function() {
data.result = true;
sendMessage(data);
});
}
El método de utilidad DownloadProcess
crea una solicitud xhr para obtener datos del servidor multimedia.
espera el estado de finalización. Esto inicia la devolución de llamada de carga que verifica el contenido recibido
y guarda los datos de forma local con la función 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);
}
);
Cuando finaliza el proceso de descarga, MediaExplorer
actualiza la lista de archivos multimedia y los archivos multimedia.
panel del árbol del reproductor.