2016-01-14 1 views
1

Мое Android-приложение показывает электронную книгу html5 в WebView.
У меня есть ZIP-файл, содержащий электронную книгу со всеми ее ресурсами: текст, изображения и аудио (mp3-файлы).
Для разблокировки книги я использую shouldInterceptRequest(), которая перехватывает файл: /// ... запросы и возвращает данные через объект WebResourceResponse. Код отлично подходит для текста и изображений.
Когда я получаю аудиоресурсы, я получаю ошибки во время выполнения, и аудиофайл не воспроизводится.
Примечание. Я вижу, что распакованный файл возвращается с правильным размером (около 10 МБ).Аудио не работает в Android WebView с использованием shouldInterceptRequest()

Сообщения об ошибках я получаю:
cr_MediaResourceGetter Файл не существует
cr_MediaResourceGetter Невозможно настроить Extractor метаданные

Мой HTML код для аудио:

<div xmlns="http://www.w3.org/1999/xhtml"> 
 
    <p style="text-align:center;margin:0px;"> 
 
    <audio controls="controls" src="../Audio/01-AudioTrack-01.mp3">Your browser does not support the audio tag.</audio> 
 
    <br /> 
 
    </p> 
 
</div>

Мой Android Код:

setWebViewClient(new WebViewClient() 
    { 
    @Override 
    public WebResourceResponse shouldInterceptRequest(WebView view, final String url) 
    { 
     String urlWithoutAnchor = URLUtil.stripAnchor(url); 
     String fileName = urlWithoutAnchor; 

     try { 
      byte [] resource = tbxPool.getResource(fileName); 
     /* SIMPLE VERSION without calling setResponseHeaders(): 
      return new WebResourceResponse(mimeType, "UTF-8", new ByteArrayInputStream(resource)); 
      */ 
      WebResourceResponse returnedMediaResource = new WebResourceResponse(mimeType, "UTF-8", new ByteArrayInputStream(resource)); 
      if (mimeType.toLowerCase().startsWith("audio")) { 
       Map<String, String> responseHeaders = new HashMap<String, String>(); 

       responseHeaders.put("Content-Type", mimeType); 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//2CLEAN 
        returnedMediaResource.setResponseHeaders(responseHeaders); 
        Logger.v(TAG, "Response Headers added to audio resource"); 
       } 
       else { 
        //TODO: Handle else for API<21. Toast? 
       } 
      }        
      return returnedMediaResource; 
     } catch (IOException e) { 
      Logger.e(TAG, "failed to load resource "+fileName,e); 
      return null; 
     } 
    } 
} 

Environment
Android 6.0.1 (Nexus 5) Android System WebView версия 47

Требование Разъяснение
Звук играть в браузер, такой как документ html5, должен, не обойдя внешний проигрыватель.

Вопрос:
Что я делаю неправильно ?! Спасибо заранее!

ответ

1

Обходной я нашел эту проблему не шикарно, но это только один, который работал для меня: Написать аудиофайл сд карты :(
Stage 1). Когда shouldInterceptRequest() вызывается с главой URL-адрес.
Глава первая перехвачена (перед перехватом других ресурсов раздела (изображения, аудио, шрифты, ..)
Когда глава перехвачена, мы ищем html для тега <audio>. Если он найден, заменим относительный путь (например, SRC = "../ Audio/abc.mp3") с абсолютным путем (например, SRC = "/ storage/tmp/abc.mp3")

Этап 2): Когда shouldInterceptRequest() вызывается с звуковой url.
Ваше внимание. Как и все обходные пути, это немного сложно (но работает!):
После этапа 1) звуковой url будет абсолютным url (абсолютный url - это то, что теперь написано в измененном html).
Теперь нам нужно сделать 2 вещи:
a) прочитайте аудиофайл с застегнутого на полу epub.
Для этого нам нужно «обмануть» код и прочитать аудиофайл со своего исходного зашифрованного относительного URL-адреса, например. »../Audio/abc.mp3" в нашем примере (хотя shouldInterceptRequest была вызвана с „/storage/tmp/abc.mp3“).
б) После прочтения архивного звукового файла, записать его в хранилище (SDCard)

Этап 3) Когда shouldInterceptRequest() вызывается с url главы, Мы удаляем временные аудиофайлы Примечание: если вы будете следовать этому коде, вы увидите, что это шаг 0) в shouldInterceptRequest(), выполненный до этапа 1), но я нашел это понятнее объяснить выше

if (isChapterFile(mimeType)) { 
    deleteTempFiles(); // this line is stage 3) 
     changeAudioPathsInHtml(tzis); // this line is stage 1) 

Это код:.

setWebViewClient(new WebViewClient() 
{ 
    private String tmpPath = TbxApplication.getAppPath(null) + "/tmp/"; 
    @Override 
    public WebResourceResponse shouldInterceptRequest(WebView view, final String url) 
    { 
     Logger.d(TAG, "in shouldInterceptRequest for " + url); 
     String urlWithoutAnchor = URLUtil.stripAnchor(url); 
     String mimeType = StringUtils.getFileMimeType(urlWithoutAnchor); 
     String urlWithoutBase; //the url stripped from leading 'epubBaseUrl' (base url for example:"file:///storage/.../123456.tbx") 

      if (isAudioFile(mimeType)) { //write AUDIO file to phone storage. See AUDIO WORKAROUND DOCUMENTATION  
       String storagePath = StringUtils.truncateFileScheme(url); //WebView calls shoudlInterceptRequest() with "file://..." 
       try { 
        String oEBPSAudioPath = storagePathToOEBPSAudioPath(storagePath); //e.g. change"/storage/tmp" to "OEBPS/Audio/abc.mp3" 
        byte[] audioBytes = tbxPool.getMedia(oEBPSAudioPath); 
        FileUtils.writeByteArrayToFile(audioBytes, storagePath); //TODO: To be strict, write in separate thread 
        Logger.d(TAG, String.format("%s written to %s", oEBPSAudioPath, storagePath)); 
        return null;//webView will read resource from file 
           //Note: return new WebResourceResponse("audio/mpeg", "UTF-8", new ByteArrayInputStream(audioBytes)); 
           //did NOT work,so we had to change html for audio to point to local storage & write to disk 
           //see AUDIO WORKAROUND DOCUMENTATION in this file 
       } catch (Exception e) { 
        Logger.e(TAG,e.getMessage()); 
        return null; 
       } 
      } 
      ..... 
      else { 
       if (isChapterFile(mimeType)) { //This is a CHAPTER 
        deleteTempFiles(); //Loading a new chapter. Delete previous chapter audio files. See AUDIO WORKAROUND DOCUMENTATION in this file 
        InputStream htmlWithChangedAudioPaths = changeAudioPathsInHtml(tzis); //see AUDIO WORKAROUND DOCUMENTATION in this file 
        WebResourceResponse webResourceResponse = new WebResourceResponse(mimeType, "UTF-8", htmlWithChangedAudioPaths); 
        return webResourceResponse; 
       } 

     //Changes relative paths of audio files, to absolute paths on storage 
     //see AUDIO WORKAROUND DOCUMENTATION in this file 
     private InputStream changeAudioPathsInHtml(InputStream inputStream) { 
      String inputString = StringUtils.inputStreamToString(inputStream); 
      String outputString = inputString.replaceAll("\"../Audio/", "\"" + tmpPath);// e.g. SRC="../Audio/abc.mp3" ==>SRC="/sdcard/tmp/abc.mp3"                    //where '*' stands for multiple whitespaces would be more elegant 
      return StringUtils.stringToInputStream(outputString); 
     } 

     /** Example: 
     * storagePath="/storage/tmp/abc.mp3 
     * Returns: "OEBPS/Audio/abc.mp3"*/ 
     private String storagePathToOEBPSAudioPath(String storagePath){ 
      String fileName = StringUtils.getFileName(storagePath); 
      String tbxOEBPSAudioPath = "OEBPS/Audio/" + fileName; 
      return tbxOEBPSAudioPath; 
     } 

public static void writeByteArrayToFile(byte[] byteArray, String outPath) { 
    try { 
     File file = new File(outPath); 
     FileOutputStream fos = new FileOutputStream(file); 
     fos.write(byteArray); 
     fos.close(); 
    } catch (IOException e) { 
     Logger.e(TAG, String.format("Could not write %s", outPath)); 
    } 
}