Работа HTML 5 audio на Андроид в WebView
- Подробности
- Категория: Разработка
- Опубликовано 30.11.-0001 02:30
В этом материале мы коснёмся звукового сопровождения игр и приложений, которые строятся на технологии HTML под Андроид. Эта тема весьма спорная и очень неоднозначная и в этой статье мы поговорим о тонкости передачи звука в HTML, в вашей игре или приложении.
Тэг audio
Тэг audio ровным счётом как и тэг video поддерживается Андроидом также как и большинство фич HTML 5. И качество и стабильность работы вроде бы не должна вызывать противоречий... Вроде бы...
Казалось бы HTML5 и все дела должны присутствовать и работать стабильно, но к сожалению HTML 5 audio и video были реализованы несколько криво в WebView Андроида.
Дело в том что эти два HTML5 тэга работают безукоризненно с удалёнными данными. Например:
<audio src="http://site.com/sound.mp3"></audio>
А вот только речь заходит за использование локальных данных тут уже всё, неизвестно по каким причинам, но данные с HTML страницы в тэгах audio и video не обнаруживаются на локальном устройстве. Иными словами, поместили вы страницу в папку assets вашего проекта и рядом с ним файл sound mp3, то такой код:
<audio src="/sound.mp3"></audio>
Работать не будет. Вот такая вот беда с относительными путями. Какой пусть поставить чтобы всё нормальзовалось, что и как сделать я сам не знаю, но запустить на нативном HTML локальный звук, к сожалению так и не удалось.
Также стоит отметить что автостарт аудио на Андроиде также не работает.
Насколько я знаю embed и object с аудио в андроид тоже не работают.
Однако расстраиваться не стоит и есть альтернативные пути запуска звуков из вашего HTML5 приложения.
Свистопляски
1. Использование кодированного в base64 файла самого звука.
Если кто-то не знал, то браузерами и в том числе мобильными (и WebView) поддерживается использования кодированной base64 строки с содержанием самого звука.
<audio src="data:audio/x-wav;base64,UklGRuwQVZFZ ... CYBLgPiAD"></audio>
Грубо говоря мы просто даём данные обработчику браузера немного в другом виде. Все параметры естественно также работают. Можно яваскриптом создавать файл и удалять его по окончании:
var Sound = (function () {
var df = document.createDocumentFragment();
return function Sound(src) {
var snd = new Audio(src);
df.appendChild(snd); // keep in fragment until finished playing
snd.addEventListener('ended', function () {df.removeChild(snd);});
snd.play();
return snd;
}
}());
// Используем
var snd = Sound("data:audio/wav;base64," + base64string);
Для вызова из ссылки A, можно расширить класс WebViewClient:
vw.setWebViewClient(new WebViewClient() {
public MediaPlayer mp;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.endsWith(".mp3")){
//url = url.replace("file:///android_asset/webpages/";, "");
try {
AssetFileDescriptor afd = getAssets().openFd(url);
mp = new MediaPlayer();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
mp.start();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if (url.indexOf("tel:") > -1) {
startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
} else {
view.loadUrl(url);
}
return true;
}
});
Также можете почитать комментарии к
Некоторым ещё помогает метод webview loadDataWithBaseURL(). Его сть указать базовый адрес. Не смог применить его в этом плане. У кого получится - отпишитесь в комментариях.
Как бы не было грустно, но я пока нашёл единственный хороший способ воспроизводить звук из WebView - Javescript мост.
Java-Javascript мост
Мы уже писали о создании моста в статьях, поэтому сразу к делу:
Обозначаем переменную:
MediaPlayer mp = new MediaPlayer();
А затем пишем функцию:
@JavascriptInterface
public void playBeep(String url) {
try {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = new MediaPlayer();
}
else{
AssetFileDescriptor descriptor = mContext.getAssets().openFd(url);
mp.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
descriptor.close();
mp.prepare();
mp.setVolume(1f, 1f);
mp.setLooping(true);
mp.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Теперь вам осталось только прикрутить это к вашему проекту и всё будет нормально.
Если у вас есть что добавить - обязательно пишите в комментариях.