Bu dokümanın amacı, Sencha Ext JS ile Chrome Uygulamaları geliştirmeye başlamanızı sağlamaktır. bahsedeceğim. Bu hedefe ulaşmak için Sencha'nın geliştirdiği medya oynatıcı uygulamasını inceleyeceğiz. Kaynak kodu ve API Belgeleri'ni GitHub'da bulabilirsiniz.
Bu uygulama, kullanıcının PC'ye bağlı medya cihazları da dahil olmak üzere kullanılabilir medya sunucularını keşfeder ve ağ üzerinden medyayı yöneten bir yazılımdır. Kullanıcılar medyaya göz atabilir, ağ üzerinde içerik oynatabilir ve kaydedebilir. çevrimdışı.
Sencha Ext JS kullanarak medya oynatıcı uygulaması oluşturmak için yapmanız gereken önemli şeyler:
- Manifest oluşturun,
manifest.json
. background.js
adlı etkinlik sayfasını oluşturun.- Sandbox uygulamasının mantığı.
- Chrome uygulaması ile korumalı alana alınan dosyalar arasında iletişim kurar.
- Medya sunucularını keşfedin.
- Medya keşfedin ve oynatın.
- Medyayı çevrimdışına kaydet.
Manifest oluştur
Tüm Chrome uygulamaları için Chrome'un başlatması gereken bilgileri içeren bir manifest dosyası gerekir. Manifest dosyasında belirtildiği gibi, medya oynatıcı uygulaması "çevrimdışı_enabled" medya öğelerini yerel olarak kaydedilir, kullanılır ve bağlantı durumu dikkate alınmaksızın oynanabilir.
"Korumalı alan" alanı, uygulamanın ana mantığını benzersiz bir kaynakta korumalı alana almak için kullanılır. Tümü korumalı alana alındı içerik, Chrome Uygulaması İçerik Güvenliği Politikası'ndan muaf olsa da Chrome Uygulaması API'leri Manifest, izin; medya oynatıcı uygulaması socket API'yi kullanarak ağ üzerinden bir medya sunucusuna bağlanabilirsiniz.
{
"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"
]
}
]
}
Etkinlik sayfası oluştur
Tüm Chrome Uygulamaları'nın başlatılması için background.js
gereklidir. Medya oynatıcının ana sayfası
index.html
, belirtilen boyutlarla bir pencerede açılır:
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;
});
});
Korumalı alan uygulamasının mantığı
Chrome Uygulamaları, katı bir İçerik Güvenliği Politikası'nı zorunlu kılan kontrollü bir ortamda çalışır
(İGP). Medya oynatıcı uygulamasının Ext JS bileşenlerini oluşturmak için daha yüksek ayrıcalıklara ihtiyacı var. Alıcı:
CSP'ye uymalı ve uygulama mantığını yürütmelidir. Uygulamanın ana sayfası (index.html
),
bir korumalı alan ortamı olarak işlev görür:
<iframe id="sandbox-frame" sandbox="allow-scripts" src="sandbox.html"></iframe>
iframe, Ext JS için gerekli dosyaları içeren sandbox.html adresine işaret eder. uygulama:
<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>
app.js komut dosyası, tüm Ext JS kodunu yürütür ve medya oynatıcı görünümlerini oluşturur. Bu tarihten itibaren
komut dosyası korumalı alana alındıysa Chrome Uygulama API'lerine doğrudan erişemez. app.js
arasındaki iletişim
ve korumalı alana alınmamış dosyalar da HTML5 Post Message API kullanılarak yapılır.
Dosyalar arasında iletişim kurma
Medya oynatıcı uygulamasının Chrome Uygulama API'lerine erişebilmesi için ağda medya sorgulaması gibi işlemler yapmak üzere
sunucular, app.js
iletileri index.js dosyasına gönderir. Korumalı alana alınan app.js
uygulamasından farklı olarak index.js
şunları yapabilir:
doğrudan Chrome Uygulama API'lerine erişebilir.
index.js
, iframe'i oluşturur:
var iframe = document.getElementById('sandbox-frame');
iframeWindow = iframe.contentWindow;
Ayrıca, korumalı alana alınan dosyalardan gelen mesajları dinler:
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);
Aşağıdaki örnekte app.js
, index.js
adlı alıcıya anahtar isteğinde bulunan bir mesaj gönderiyor
"extension-baseurl":
Ext.data.PostMessage.request({
key: 'extension-baseurl',
success: function(data) {
//...
}
});
index.js
isteği alır, sonucu atar ve Temel URL'yi geri göndererek yanıt verir:
function extensionBaseUrl(data) {
data.result = chrome.extension.getURL('/');
iframeWindow.postMessage(data, '*');
}
Medya sunucularını keşfedin
Medya sunucularını keşfetmenin pek çok yönü vardır. Keşif iş akışı genel hatlarıyla
Mevcut medya sunucularını aramak için bir kullanıcı işlemi tarafından başlatılır. MediaServer denetleyicisi
index.js
adresine bir ileti gönderdiğinde; index.js
bu mesajı dinler ve alındığında telefon eder
Upnp.js.
Upnp library
, medya oynatıcı uygulamasını herhangi bir cihaza bağlamak için Chrome Uygulaması socket API'sini kullanır.
bulduğunda ve medya sunucusundan medya verileri aldığında. Upnp.js
tarafından da kullanılıyor
Medya sunucusu verilerini ayrıştırmak için soapclient.js. Bu bölümün geri kalanında,
daha ayrıntılı değineceğiz.
Mesajı yayınla
Kullanıcı, medya oynatıcı uygulamasının ortasındaki Medya Sunucuları düğmesini tıkladığında MediaServers.js
discoverServers()
araması yapıyor. Bu işlev öncelikle bekleyen keşif isteklerini ve
true ise yeni isteğin başlatılabilmesi için bunları iptal eder. Ardından kumanda,
Bir anahtar upnp keşfi ve iki geri arama dinleyicisi ile index.js
:
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');
}
});
upnpKeşfet() işlevini çağırın
index.js
, "upnp-Keşfet" şarkısını dinliyor app.js
adlı kişiden mesaj var ve telefonla yanıt veriyor
upnpDiscover()
. Bir medya sunucusu keşfedildiğinde index.js
, medya sunucusu alanını çıkarır
sunucuyu yerel olarak kaydeder, medya sunucusu verilerini biçimlendirir ve verileri
MediaServer
kumandası.
Medya sunucusu verilerini ayrıştır
Upnp.js
yeni bir medya sunucusu keşfettiğinde cihazın açıklamasını alıp
Medya sunucusu verilerine göz atmak ve ayrıştırmak için bir Soap isteği; soapclient.js
, medya öğelerini ayrıştırır
etiket adına göre bir dokümana ekleyebilirsiniz.
Medya sunucusuna bağlan
Upnp.js
, keşfedilen medya sunucularına bağlanır ve medya verilerini Chrome Uygulama yuvasını kullanarak alır.
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);
});
});
});
Medya keşfetme ve oynatma
MediaGezgin denetleyicisi, medya sunucusu klasöründeki tüm medya dosyalarını listeler ve
medya oynatıcı uygulama penceresinde içerik haritası gezinmesinin güncellenmesinden sorumludur. Kullanıcı
bir medya dosyası seçtiğinde kumanda, index.js
uygulamasına "play-media" öğesi içeren bir mesaj gönderir anahtar:
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
bu yayın mesajını dinler ve playMedia()
numaralı telefonu arayarak yanıt verir:
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);
}
Medyayı çevrimdışına kaydet
Medyayı çevrimdışı kaydetmeyle ilgili zor işlemlerin çoğu filer.js kitaplığı tarafından gerçekleştirilir. Web sitemiz g.co/newsinitiative/labs üzerinden bu kitaplığı filer.js tanıtımı'nda bulabilirsiniz.
İşlem, kullanıcı bir veya daha fazla dosya seçip "Çevrimdışı al" işlemini başlattığında başlar eyleme dökülebilir.
MediaGezgin denetleyicisi, index.js
adresine "download-media" anahtarı içeren bir mesaj gönderir;
index.js
bu mesajı dinler vedownloadMedia()
indirme işlemi:
function downloadMedia(data) {
DownloadProcess.run(data.params.files, function() {
data.result = true;
sendMessage(data);
});
}
DownloadProcess
yardımcı program yöntemi, medya sunucusundan veri almak için bir xhr isteği oluşturur ve
tamamlanma durumunu bekler. Bu işlem, alınan içeriği kontrol eden onload geri çağırmasını başlatır
ve filer.js
işlevini kullanarak verileri yerel olarak kaydeder:
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);
}
);
İndirme işlemi tamamlandığında MediaExplorer
, medya dosyası listesini ve medyayı günceller.
oyuncu ağacı paneli.