Этот ответ относится только к Vimeo. После примерно дюжины неудачных попыток вот что у меня работает. Возможно, это поможет кому-то еще. Тысяча извинений первоначальным авторам других ответов SO. Я «позаимствовал» несколько шаблонов ниже — просто подумал, что было бы удобно иметь все это в одном месте и не требовать их для своего собственного кода.
Во-первых, я не нашел способа встроить проигрыватель Vimeo (т. е. вы не можете получить доступ к потоку mp4 напрямую — по крайней мере, не легко и надежно — я почти уверен, что это сделано намеренно). Во-вторых, Vimeo предлагает библиотеку javascript для инструментов своего проигрывателя, и ее использование неизбежно. Осторожно, для этого требуется передача сообщений, что является новой функцией браузера. Это задокументировано на их странице API. В-третьих, как описано в другом месте на SO, вам нужно быть очень осторожным, чтобы дождаться готовности частей стека и не прыгать с пистолета. В-четвертых, проигрыватель Vimeo включает в себя особенно бесполезное фоновое изображение, означающее, что плагин отсутствует или сломан (небольшой кадр фильма, общий значок для этого). Что на самом деле означает, так это то, что ваш javascript где-то взорвался, и вообще ничего не работает. Если вы видите небольшой фрагмент пленки на пустом экране, проверьте свой javascript.
Шаг 1. Настройте WebView. У вас это правильно выше. Для справки, вот что я использовал.
mWebView = new WebView((Context) this);
mWebView.setLayoutParams(new LayoutParams(windowWidth, windowHeight));
mWebView.getSettings().setJavaScriptEnabled(true);
// Watch the sdk level here, < 12 requires 'false
// Wanted to force HTML5/264/mp4, you may want flash
// where still available
mWebView.getSettings().setPluginState(PluginState.OFF);
mWebView.getSettings().setLoadWithOverviewMode(true);
mWebView.getSettings().setUseWideViewPort(true);
mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
wcc = new MyWebChromeClient();
mWebView.setWebChromeClient(wcc);
wvc = new MyWebViewClient();
mWebView.setWebViewClient(wvc);
Шаг 2. Вам нужен WebChromeClient, если вы хотите, чтобы видео работало в WebView. Это задокументировано здесь: http://developer.android.com/reference/android/webkit/WebView.html (см. Поддержка HTML-видео).
Опять же, для справки вот то, что я использовал.
private class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int progress) {
if(progress == 100) {
// Your page is loaded, but not visible,
// add whatever navigation elements you plan to use here.
// N.B. these are JAVA, not JS nav elements
}
}
@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
// I like to watch in the console. And, since it was
// a very convenient way to monitor the javascript, I
// use it for that too. Purists will object, no doubt
if(cm.message().equalsIgnoreCase("EVENT -- Finish")) {
Log.i(TAG, "---> Finishing . . .");
// Depart the activity
finish();
} else {
Log.d(TAG, " **Console ["+cm.sourceId()+"] ("+cm.lineNumber()+") ["+cm.message()+"]");
}
return(true);
}
@Override
public View getVideoLoadingProgressView() {
// Something entertaining while the bytes arrive
Log.i(TAG, " -------------> Loading Progress . . . ");
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return(inflater.inflate(R.layout.loading_video, null));
}
@Override
public void onShowCustomView(View v, WebChromeClient.CustomViewCallback callback) {
// With great sadness, I report that this never fires.
// Neither does the 'hide'.
}
@Override
public void onHideCustomView() {
}
}
WebViewClient выглядит так:
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String injection = injectPageMonitor();
if(injection != null) {
Log.d(TAG, " ---------------> Page Loaded . . .");
Log.d(TAG, " Injecting . . . ["+injection+"]");
view.loadUrl(injection);
}
}
}
Шаг 3. Вам нужно создать небольшой фрагмент Javascript, чтобы запустить проигрыватель. Я использовал это:
public String injectPageMonitor() {
return( "javascript:" +
"jQuery(document).ready( function() { " +
"console.log(' === Page Ready ===> Setting up');" +
"console.log(' ==== Sending PLAY Command ===');" +
"var froogaloop = $f('froog');" +
"setTimeout(function() { froogaloop.api('play'); }, 3000);" +
"});");
}
Быстрое объяснение. . . Я использую jQuery в своем JS, это будет ниже. Это только для удобства, вы можете сделать прямой JS, если хотите облегчить нагрузку. Обратите внимание, что после того, как все остальное будет готово, скрипт ждет еще 3 секунды, прежде чем сработает. В моменты моей слабости я представляю, что у добрых людей в Vimeo есть неработающий обратный вызов «готово». 3 секунды, кажется, делают это.
Шаг 4. Вам нужно немного HTML и JavaScript на странице. Я поместил его в текстовый файл внутри ресурсов (raw/vimeo_frame.html). Файл выглядит так:
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript">jQuery.noConflict();</script>
<script src="http://a.vimeocdn.com/js/froogaloop2.min.js"></script>
<script type="text/javascript">
jQuery(document).ready( function() {
var showing_player = false;
var froogaloop = $f('froog');
console.log(' === Page Ready ===> Setting up');
jQuery('.froog_container_class').hide();
jQuery('.console').css('height', '100%');
froogaloop.addEvent('ready', function() {
console.log('==== PLAYER READY ====> Setting Play Callback');
froogaloop.addEvent('play', function(data) {
console.log('EVENT -- Play');
/* No idea why, but if the player isn't displayed, it goes
straight to 'pause'. Probably a feature. So I give it 4x4px
to do it's thing during setup */
jQuery('.froog_container_class').show();
jQuery('.froog_container_class').css('height', '4px');
jQuery('.froog_container_class').css('width', '4px');
jQuery('.froog_container_class').css('overflow', 'hidden');
});
/* I don't want to reveal the video until it is actually
playing. So I do that here */
var showingPlayer = false;
froogaloop.addEvent('playProgress', function(data) {
if(!showingPlayer && data.percent > 0) {
showingPlayer = true;
jQuery('.froog_container_class').show();
jQuery('.froog_container_class').css('height', '_windowHeight');
jQuery('.froog_container_class').css('width', '_windowWidth');
/* Most tablets I tested aren't quick enough to make this work
but one can still hope */
jQuery('#loading').fadeOut('slow');
}
});
});
});
</script>
</head>
<body>
<style>
body {
background-image: url('http://<SomethingEntertainingToWatch>.png');
background-size: contain;
}
.mask {
float: left;
height: _windowHeight;
width: _windowWidth;
z-index: 100;
background: transparent;
display: inline;
position: absolute;
top: 0;
left: 0;
}
.froog_container_class {
position: absolute;
height: _windowHeight;
width: _windowWidth;
left: 0;
top: 0;
display: inline;
z-index: 1;
}
#froog {
display: inline;
height: _windowHeight;
width: _windowWidth;
postion: absolute;
top: 0;
left: 0;
}
</style>
<div id="loading" class="loading"><h1>Loading</h1><img class="loading_anim" src="http://foo.bar.com/assets/global/loading.gif"/>
</div>
<!-- Completely optional, I put a div in front of the player to block controls -->
<div id="mask" class="mask">
</div>
<div id="froog_container" class="froog_container_class">
<iframe id="froog" src="_targetUrl?api=1&title=0&byline=0&portrait=0&player_id=froog" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
</div>
</body>
</html>
И я загружаю этот html-файл так:
public String genMainHTML() {
String code = null;
try {
Resources res = getResources();
InputStream in_s = res.openRawResource(R.raw.vimeo_frame);
byte[] b = new byte[in_s.available()];
in_s.read(b);
code = new String(b);
} catch (Exception e) {
e.printStackTrace();
}
if(code != null) {
code = code.replaceAll("_windowHeight", "" + windowHeight + "px");
code = code.replaceAll("_windowWidth", "" + windowWidth + "px");
code = code.replaceAll("_targetUrl", targetUrl);
return(code);
} else {
return(null);
}
}
И введите его так:
mDomain = "http://player.vimeo.com";
mWebView.requestFocus(View.FOCUS_DOWN);
targetUrl = extras.getString("URL");
String meat = genMainHTML();
mWebView.loadDataWithBaseURL(mDomain, meat, "text/html", "utf-8", null);
setContentView(mWebView);
Вау! Когда WebView готов, идут html и js, включая iframe с проигрывателем Vimeo. Когда документ загрузится, то ждем готовности плеера. Когда проигрыватель готов, мы добавляем слушателей. И через 3 секунды мы запускаем метод API play.
Полировщики яблок в зале могут задаться вопросом, для полноты картины, как можно остановить видео? Два бита. Во-первых, когда он заканчивается, я останавливаю его, наблюдая за выводом консоли сообщения, которое я отображаю. Таким образом:
public String injectPageFinisher() {
return( "javascript:" +
"jQuery(document).ready( function() { " +
"console.log(' === Page Ready ===> Tearing down');" +
"console.log(' ==== Sending PAUSE Command ===');" +
"var froogaloop = $f('froog');" +
"froogaloop.api('pause');" +
"jQuery('#froog_container').html('');" +
"});");
}
Который можно вставить так:
@Override
public void onPause() {
super.onPause();
if(isFinishing()){
// Unload the page
if(mWebView != null) {
Log.i(TAG, " ------> Destroying WebView");
mWebView.destroy();
}
}
finish();
}
Во втором бите видео завершает свое маленькое «я». Таким образом, в вышеприведенном файле vimeo_frame.html сразу после обратного вызова play я добавил:
froogaloop.addEvent('finish', function(data) {
console.log('EVENT -- Finish');
});
И в Activity я немного понаблюдал за этим — см. выше в переопределении onConsoleMessage.
ОДНАКО -- на момент написания этой статьи я так и не решил одну надоедливую проблему. MediaPlayer продолжает жить после того, как WebView и все его потомки исчезли. Я уверен, что это создает некоторые проблемы, но я еще не определил их.
person
Ted Collins
schedule
14.09.2012