Работа HTML 5 audio на Андроид в WebView

В этом материале мы коснёмся звукового сопровождения игр и приложений, которые строятся на технологии 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 строки с содержанием самого звука.

Вот пример кода, где можно сгенерировать wave-волну с помощью яваскрипт и сразу же её воспроизвести как раз в виде строки кодированных данных. Проинксперировав элемент в браузере вы убедитесь что выглядит финальный HTML аудио код так:

<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();
}
}

Теперь вам осталось только прикрутить это к вашему проекту и всё будет нормально.

Если у вас есть что добавить - обязательно пишите в комментариях.


Добавить комментарий


Защитный код
Обновить

Карта сайта